Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
7d9df71
ci: verify workflow write permission
seonghobae Aug 27, 2026
480a48c
ci: stage ELUNVERA baseline payload 01
seonghobae Aug 27, 2026
210bc08
ci: stage ELUNVERA baseline payload 02
seonghobae Aug 27, 2026
b3e3c86
ci: stage ELUNVERA baseline payload 03
seonghobae Aug 27, 2026
58817b3
ci: stage ELUNVERA baseline payload 04
seonghobae Aug 27, 2026
a56287c
ci: stage ELUNVERA baseline payload 05
seonghobae Aug 27, 2026
23e1e5b
ci: stage ELUNVERA baseline payload 06
seonghobae Aug 27, 2026
a5e4845
ci: stage ELUNVERA baseline payload 07
seonghobae Aug 27, 2026
6d9df83
ci: stage ELUNVERA baseline payload 08
seonghobae Aug 27, 2026
5aed277
ci: stage ELUNVERA baseline payload 09
seonghobae Aug 27, 2026
2f642e1
ci: materialize verified ELUNVERA documentation baseline
seonghobae Aug 27, 2026
bf6a113
ci: pause ELUNVERA baseline bootstrap during payload repair
seonghobae Aug 27, 2026
dbe1387
ci: repair ELUNVERA baseline payload 07
seonghobae Aug 27, 2026
47ea3f8
ci: rerun verified ELUNVERA baseline materialization
seonghobae Aug 27, 2026
e8166dc
docs: establish ELUNVERA product and technical baseline
github-actions[bot] Aug 27, 2026
1c31ca4
ci: stage ELUNVERA contract repair patch
seonghobae Aug 29, 2026
3572e83
ci: run bounded ELUNVERA contract repair
seonghobae Aug 29, 2026
3eab23a
fix: align HTTP and event contract coherence
github-actions[bot] Aug 29, 2026
8dd9857
fix: require event provenance
seonghobae Aug 29, 2026
0601ef8
ci: verify required event provenance
seonghobae Aug 29, 2026
fe5b69c
chore: refresh required-provenance manifest
github-actions[bot] Aug 29, 2026
14351f1
ci: add exact-head document contract validation
seonghobae Aug 29, 2026
cbf281d
ci: refresh exact-head document manifest
seonghobae Aug 29, 2026
208f980
chore: refresh exact-head document manifest
github-actions[bot] Aug 29, 2026
bc7e86c
ci: trigger exact-head document contract validation
seonghobae Aug 29, 2026
b0dcb30
ci: repair remaining contract review findings
seonghobae Aug 29, 2026
41b7dd4
ci: fix bounded review repair workflow
seonghobae Aug 29, 2026
538e563
ci: surface and commit bounded review repairs
seonghobae Aug 29, 2026
a71a5da
ci: make review repair atomic
seonghobae Aug 29, 2026
d0ce17e
ci: launch independent atomic review repair
seonghobae Aug 29, 2026
44d7885
ci: stage deterministic contract review repair
seonghobae Aug 29, 2026
88ea9a9
ci: execute deterministic contract review repair
seonghobae Aug 29, 2026
5e8d712
ci: reconcile reviewed contract baseline atomically
seonghobae Aug 29, 2026
4f708cf
ci: finalize permanent contract validation baseline
seonghobae Aug 29, 2026
d317c4a
ci: gate PR 2 on exact-head evidence
seonghobae Aug 29, 2026
e4812e5
ci: enable review on develop pull requests
seonghobae Aug 29, 2026
8a42f56
docs(metadata): add Ask DeepWiki badge
seonghobae Sep 1, 2026
695acca
docs(metadata): add public documentation landing page
seonghobae Sep 1, 2026
1a82844
ci: remove one-shot reconciliation workflow
seonghobae Sep 2, 2026
3f068c8
ci: remove superseded reconciliation workflow
seonghobae Sep 2, 2026
11cc8cb
ci: remove superseded reconciliation workflow
seonghobae Sep 2, 2026
da7e64a
ci: remove temporary review repair workflow
seonghobae Sep 2, 2026
c5a0d39
ci: remove temporary review repair workflow
seonghobae Sep 2, 2026
10ca2d3
ci: remove temporary review repair workflow
seonghobae Sep 2, 2026
f8eda92
ci: remove one-shot review repair script
seonghobae Sep 2, 2026
9df5819
docs: license ELUNVERA source under Apache-2.0
seonghobae Sep 2, 2026
9484adf
docs: make ELUNVERA license boundary explicit
seonghobae Sep 2, 2026
4a152c4
docs: accept Apache-2.0 source license decision
seonghobae Sep 2, 2026
1a4ba8d
docs: record accepted license ADR
seonghobae Sep 2, 2026
c7f837f
docs: record source license and public landing
seonghobae Sep 2, 2026
a1b9070
docs: correct validation inventory and schema claim
seonghobae Sep 2, 2026
33e6f33
docs: close repository source-license gap
seonghobae Sep 2, 2026
1523282
docs: make public landing license-aware
seonghobae Sep 2, 2026
9fc86f5
ci: validate docs on canonical main PRs
seonghobae Sep 2, 2026
b9101a7
ci: review canonical main pull requests
seonghobae Sep 2, 2026
40c694a
docs: align integration branch with protected main
seonghobae Sep 2, 2026
6b1c71c
docs: point public navigation at canonical main
seonghobae Sep 2, 2026
8703232
docs: keep license ADR Proposed until integration
seonghobae Sep 2, 2026
ba50300
docs: align ADR index with Draft foundation status
seonghobae Sep 2, 2026
82e6488
docs: reconcile governance and Draft decision evidence
seonghobae Sep 2, 2026
9fcb3c2
docs: record canonical-main governance repairs
seonghobae Sep 2, 2026
c1bddee
chore: reseal exact foundation manifest
seonghobae Sep 2, 2026
df5bc9f
docs: align agent base with canonical main
seonghobae Sep 2, 2026
6a011d9
docs: align contribution base with canonical main
seonghobae Sep 2, 2026
8f33bb9
docs: make PRD branch authority canonical
seonghobae Sep 2, 2026
3f5966e
docs: align roadmap with canonical main
seonghobae Sep 2, 2026
2723797
docs: align foundation spec with canonical main
seonghobae Sep 2, 2026
728c416
docs: align implementation plan with canonical main
seonghobae Sep 2, 2026
cff9c6f
docs: record canonical branch authority reconciliation
seonghobae Sep 2, 2026
c2a1dd9
chore: reseal canonical branch manifest
seonghobae Sep 2, 2026
3cbe9e0
ci: guard canonical main authority
seonghobae Sep 2, 2026
86b87bf
docs: record branch-authority contract guard
seonghobae Sep 2, 2026
862222a
chore: reseal branch-authority manifest
seonghobae Sep 2, 2026
3dce118
test(docs): fail closed on performance and locale contract drift
seonghobae Sep 2, 2026
589c572
docs(prd): adopt eight-locale and 20ms buyer contracts
seonghobae Sep 2, 2026
d9917c6
docs(trd): bind runtime, locale and translation contracts
seonghobae Sep 2, 2026
8675051
docs(ux): define eight-locale versioned translation UX
seonghobae Sep 2, 2026
2dea0a4
docs(test): enforce realistic 20ms and eight-locale evidence
seonghobae Sep 2, 2026
73f9b06
docs(gap): reconcile commercialization performance and i18n gaps
seonghobae Sep 2, 2026
7c0098c
docs(changelog): record commercialization contract repair
seonghobae Sep 2, 2026
d7cd411
chore(manifest): reseal commercialization contract evidence
seonghobae Sep 2, 2026
7a4928a
ci(actions): restamp current head after startup failure
seonghobae Sep 4, 2026
e964db0
chore: refresh head after Actions startup failure
seonghobae Sep 4, 2026
223228f
ci(actions): scope document checks by pull request
seonghobae Sep 4, 2026
4a12ecd
ci: enforce tracked text hygiene
seonghobae Sep 30, 2026
85f0ff3
fix: harden relationship evidence contract
seonghobae Sep 30, 2026
5a51442
fix: address exact-head contract review
seonghobae Sep 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
reviews:
auto_review:
enabled: true
base_branches:
- main
- develop
review_status: true
48 changes: 48 additions & 0 deletions .cwl/data-management.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
schema_version: '1.0'
repository: ContextualWisdomLab/ELUNVERA
product_name: ELUNVERA
authoritative_data_assets:
- asset_code: customer_relationship_record
description: Tenant-scoped parties, accounts, roles, relationships, evidence, and history.
data_classification: restricted_personal_and_commercial
system_of_record: true
- asset_code: commercial_opportunity_record
description: Opportunity process, stage, value, forecast, stakeholder, and outcome history.
data_classification: confidential_commercial
system_of_record: true
- asset_code: complaint_outcome_record
description: Complaint, remedy, customer response, satisfaction observation, and outcome history.
data_classification: restricted_customer_case
system_of_record: true
data_owner_role: elunvera_product_owner
data_steward_role: tenant_data_steward
critical_data_elements:
- party_identity_reference
- relationship_truth_status
- relationship_valid_time
- account_owner_assignment
- opportunity_stage_history
- monetary_amount_and_currency
- communication_preference
- complaint_status
quality_rule_references:
- docs/DATA_MODEL.md#18-data-quality-invariants
- docs/TEST_STRATEGY.md
retention_policy_references:
- docs/PRIVACY.md#8-retention-and-disposition
- docs/adr/0015-retention-disposition.md
lineage_producers:
- elunvera_api
- elunvera_worker
lineage_consumers:
- semantic_data_portal
- lineageweave
applicable_knowledge_areas:
- data_governance
- data_quality
- metadata_management
- data_security
- data_integration_and_interoperability
assessment_exclusions:
- code: production_runtime_evidence
reason: The repository baseline contains no implemented runtime.
38 changes: 38 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
## Product outcome

Describe the buyer- or operator-visible problem closed by this PR.

## Scope and boundaries

- Owning ELUNVERA responsibility:
- CWL dependencies consumed by contract:
- Explicitly excluded work:

## Evidence

- Exact head:
- Tests and commands actually run:
- Coverage and documentation denominators:
- Migration/restore/security/accessibility/model evidence, where applicable:

## Data and privacy

- Data assets and classifications changed:
- Tenant, purpose, retention, legal-hold, and export impacts:
- New event fields reviewed for PII/secrets:

## Contracts and docs

- [ ] OpenAPI/AsyncAPI/JSON Schema updated
- [ ] ADR updated or decision remains conformant
- [ ] `docs/product-technical-gap-baseline.md` updated
- [ ] `CHANGELOG.md` updated
- [ ] Doctoring and references updated

## Review gate

- [ ] Current-head checks complete
- [ ] Independent approval received
- [ ] Unresolved threads are zero
- [ ] No queued/pending/skipped check is represented as successful
- [ ] One-shot/self-modifying workflow removed after its purpose
262 changes: 262 additions & 0 deletions .github/workflows/document-contracts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
name: document-contracts

on:
pull_request:
branches:
- main
- develop
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

concurrency:
group: document-contracts-${{ github.repository }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

jobs:
validate:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out exact revision
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false

- name: Verify exact checkout
env:
EXPECTED_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
run: test "$(git rev-parse HEAD)" = "$EXPECTED_SHA"

- name: Validate document and schema contracts
shell: bash
run: |
set -euo pipefail

ruby -ryaml - <<'RUBY'
methods = %w[get post put patch delete options head trace]
openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false)
raise 'OpenAPI version mismatch' unless openapi['openapi'] == '3.2.0'
operations = []
openapi.fetch('paths').each do |path, item|
item.each do |method, operation|
next unless methods.include?(method)
operations << [method.upcase, "/v1#{path}", operation.fetch('operationId')]
end
end
expected = [
['GET', '/v1/accounts'],
['POST', '/v1/accounts'],
['GET', '/v1/accounts/{account_id}'],
['PATCH', '/v1/accounts/{account_id}'],
['POST', '/v1/relationships'],
['POST', '/v1/opportunities/{opportunity_id}/stage-transitions']
].sort
raise 'OpenAPI P0 operation mismatch' unless operations.map { |method, path, _| [method, path] }.sort == expected
raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length

relationship_request = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest')
truth_status = relationship_request.fetch('properties').fetch('truth_status')
raise 'manual relationship command permits inferred truth' if truth_status.fetch('enum').include?('inferred')
evidence_refs = relationship_request.fetch('properties').fetch('evidence_reference_ids')
raise 'evidence-backed relationship accepts no evidence' unless evidence_refs['minItems'].to_i >= 1
manual_reason = relationship_request.fetch('properties').fetch('manual_assertion_reason')
raise 'manual assertion reason must be a string' unless manual_reason['type'] == 'string'
raise 'manual assertion reason accepts empty text' unless manual_reason['minLength'].to_i >= 1
raise 'manual assertion reason accepts whitespace only' unless manual_reason['pattern'] == '.*\\S.*'

account_items = openapi.fetch('components').fetch('schemas').fetch('AccountPage').fetch('properties').fetch('items')
raise 'AccountPage items must be bounded to page_size maximum' unless account_items['maxItems'] == 100

['/accounts', '/accounts/{account_id}'].each do |path|
operation = openapi.fetch('paths').fetch(path).fetch('get')
refs = operation.fetch('parameters').filter_map { |parameter| parameter['$ref'] }
%w[ValidAt RecordedAt KnowledgeCutoff].each do |name|
raise "missing temporal parameter #{name}" unless refs.include?("#/components/parameters/#{name}")
end
headers = operation.fetch('responses').fetch('200').fetch('headers')
%w[X-ELUNVERA-Valid-At X-ELUNVERA-Recorded-At X-ELUNVERA-Knowledge-Cutoff].each do |name|
raise "missing temporal response header #{name}" unless headers.key?(name)
end
end

asyncapi = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false)
raise 'AsyncAPI version mismatch' unless asyncapi['asyncapi'] == '3.1.0'
raise 'event producer direction mismatch' unless asyncapi.fetch('operations').values.all? { |operation| operation['action'] == 'send' }
envelope = asyncapi.fetch('components').fetch('schemas').fetch('CloudEventEnvelope')
%w[dataclassification schemarevision provenanceref].each do |name|
raise "missing required event metadata #{name}" unless envelope.fetch('required').include?(name)
end
provenance = envelope.fetch('properties').fetch('provenanceref')
raise 'provenance must be a non-null string' unless provenance['type'] == 'string'
raise 'provenance must reject empty values' unless provenance['minLength'].to_i >= 1

coderabbit = YAML.safe_load(File.read('.coderabbit.yaml'), aliases: false)
review_bases = coderabbit.fetch('reviews').fetch('auto_review').fetch('base_branches')
raise 'CodeRabbit must review canonical main PRs' unless review_bases.include?('main')
RUBY

python - <<'PY'
import hashlib
import json
import re
import subprocess
from pathlib import Path
from urllib.parse import unquote

required = {
Path('docs/PRD.md'),
Path('docs/TRD.md'),
Path('docs/ARCHITECTURE.md'),
Path('docs/DATA_MODEL.md'),
Path('docs/API_CONTRACT.md'),
Path('docs/product-technical-gap-baseline.md'),
Path('docs/adr/README.md'),
Path('schemas/openapi.yaml'),
Path('schemas/asyncapi.yaml'),
}
missing = sorted(str(path) for path in required if not path.is_file())
assert not missing, missing

branch_markers = {
Path('AGENTS.md'): 'Use canonical protected `main` as the ordinary product base.',
Path('CONTRIBUTING.md'): 'Base ordinary product work on canonical protected `main`',
Path('docs/PRD.md'): '- **Primary branch:** `main`',
Path('docs/ROADMAP.md'): '`main` integration branch and protected review policy established.',
Path('docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md'): 'The ordinary integration base is canonical protected `main`',
Path('docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md'): 'through canonical protected `main`',
}
for path, marker in branch_markers.items():
assert marker in path.read_text(encoding='utf-8'), f'canonical-main authority drift: {path}'

product_contract_markers = {
Path('docs/PRD.md'): (
'p95 ≤ 20 ms',
'Korean, English, Japanese, Chinese, Vietnamese, Spanish, German, and French',
'DB-backed, versioned translation resources',
),
Path('docs/TRD.md'): (
'server/native clients fetch and cache only the screen keys they need',
'p95 ≤ 20 ms',
),
Path('docs/UX_SPEC.md'): (
'Korean, English, Japanese, Chinese, Vietnamese, Spanish, German, and French',
'DB-backed, versioned translation resources',
),
Path('docs/TEST_STRATEGY.md'): (
'p95 ≤ 20 ms',
'ko/en/ja/zh/vi/es/de/fr',
),
Path('docs/DATA_MODEL.md'): (
'party_record ||--o| person_party : specializes',
'party_record ||--o| organization_party : specializes',
'party_record ||--o| group_party : specializes',
'Exactly one party subtype record must exist and match `party_kind_code`.',
),
Path('docs/STORYBOOK_INVENTORY.md'): (
'Japanese',
'Chinese',
'Vietnamese',
'Spanish',
'German',
'French',
),
Path('docs/UML.md'): (
'Acknowledged --> Triaged',
'Investigating --> ResponseProposed',
'RemedyInProgress --> VerificationPending',
'Rejected --> Reopened',
),
Path('docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md'): (
'Consumes: a Keyverse token verifier',
'incorrect issuer, audience, signature, token type, applicable nonce',
'ko/en/ja/zh/vi/es/de/fr',
),
}
for path, markers in product_contract_markers.items():
text = path.read_text(encoding='utf-8')
for marker in markers:
assert marker in text, f'commercialization contract drift: {path}: {marker}'

plan_text = Path('docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md').read_text(encoding='utf-8')
assert plan_text.count('cargo +nightly llvm-cov') == 3
assert plan_text.count("branches['count'] == branches['covered']") == 3
assert 'cargo llvm-cov --workspace --branch' not in plan_text
uml_text = Path('docs/UML.md').read_text(encoding='utf-8')
assert 'RemedyProposed' not in uml_text
assert 'RemedyDelivered' not in uml_text
assert 'FollowUp' not in uml_text

for event_path in (
Path('schemas/events/relationship-changed-v1.schema.json'),
Path('schemas/events/opportunity-stage-changed-v1.schema.json'),
):
schema = json.loads(event_path.read_text(encoding='utf-8'))
assert schema['$schema'] == 'https://json-schema.org/draft/2020-12/schema'
assert schema['additionalProperties'] is False
assert 'recorded_at' in schema['required']
assert schema['properties']['recorded_at']['format'] == 'date-time'

trailing_whitespace = []
for path_text in subprocess.check_output(
['git', 'ls-files'], text=True
).splitlines():
payload = Path(path_text).read_bytes()
if b'\0' in payload:
continue
for line_number, line in enumerate(payload.splitlines(), 1):
if line.endswith((b' ', b'\t')):
trailing_whitespace.append(f'{path_text}:{line_number}')
assert not trailing_whitespace, (
'tracked text contains trailing whitespace: '
+ ', '.join(trailing_whitespace)
)

manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8'))
tracked = {
path
for path in subprocess.check_output(
['git', 'ls-files'], text=True
).splitlines()
if path != 'manifest.json'
}
entries = {entry['path']: entry for entry in manifest['files']}
assert manifest['self_excluded'] is True
assert manifest['file_count'] == len(entries) == len(tracked)
assert set(entries) == tracked
for path_text, entry in entries.items():
path = Path(path_text)
payload = path.read_bytes()
assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path
assert len(payload) == entry['size_bytes'], path
assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path

link_pattern = re.compile(r'(?<!!)\[[^\]]*\]\(([^)]+)\)')
for markdown_path in sorted(Path('.').rglob('*.md')):
in_fence = False
fence_count = 0
for line_number, line in enumerate(markdown_path.read_text(encoding='utf-8').splitlines(), 1):
if line.lstrip().startswith('```'):
in_fence = not in_fence
fence_count += 1
continue
if in_fence:
continue
for raw_target in link_pattern.findall(line):
target = raw_target.strip().split(' ', 1)[0].strip('<>')
if target.startswith(('http://', 'https://', 'mailto:', '#')):
continue
target = unquote(target.split('#', 1)[0])
if not target:
continue
resolved = (markdown_path.parent / target).resolve()
assert resolved.exists(), f'{markdown_path}:{line_number}: {target}'
assert fence_count % 2 == 0, f'unbalanced code fence: {markdown_path}'
PY

git diff --check
Loading
Loading