Skip to content

docs: establish ELUNVERA product and technical baseline - #2

Draft
seonghobae wants to merge 84 commits into
mainfrom
docs/product-technical-baseline
Draft

seonghobae wants to merge 84 commits into
mainfrom
docs/product-technical-baseline

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 27, 2026 •

Copy link
Copy Markdown
Contributor

ELUNVERA product and technical baseline

Product outcome

Establishes the first reviewable product and technical baseline for ELUNVERA: an evidence-centered enterprise CRM and relationship-intelligence system of record.

The baseline defines ELUNVERA’s bounded product responsibility, adjacent ContextualWisdomLab authorities, temporal/evidentiary commercial truth, and the proof required before implementation, security, accessibility, AI, commercial, or release claims may be made.

Current bounded state

This branch carries PRD/TRD, architecture, canonical data model, ERD/UML, UX and operability baselines, security/privacy/threat/test guidance, 16 Proposed ADRs, APA 7 references, OpenAPI 3.2.0, AsyncAPI 3.1.0, JSON Schema 2020-12 event payloads, CWL data-management metadata, public documentation navigation, Apache-2.0 source-license material, and a SHA-256 tracked-file integrity manifest.

It remains documentation/contracts-only. It does not claim an implemented service, database migration, user interface, customer deployment, benchmark, production security control, accessibility conformance, commercial validation, certification, or release.

Canonical-main repairs in this iteration

  • retargeted the PR from stale develop authority to protected canonical main after verifying both branches shared the same bootstrap revision;
  • updated the permanent document-contracts workflow so pull requests to main are validated and pushes on main run the contract gate;
  • updated CodeRabbit auto-review coverage for canonical-main pull requests;
  • migrated README/public navigation and reconciled AGENTS, CONTRIBUTING, PRD, ROADMAP, implementation plan, and design spec so main is the ordinary integration authority and only verified dependency stacks may temporarily target a prerequisite branch;
  • codified that repair in document-contracts: CI now checks CodeRabbit main coverage plus canonical-main authority markers so the same drift fails closed instead of depending on manual review;
  • reconciled the commercialization gap baseline with the live ruleset/branch state;
  • returned ADR-0013 from premature Accepted to Proposed while the foundation remains unmerged and aligned the ADR index/CHANGELOG;
  • resealed manifest.json after the final CI/docs repairs to all 58 tracked files other than the self-excluded manifest.

Product authority and next dependency

This PR is the canonical documentation/contract foundation prerequisite for executable PR #1. PR #1’s activation decision was separately renumbered to Proposed ADR 0017, avoiding this branch’s 0001–0016 range. Its executable delta is preserved; remaining lowercase docs/prd.md / docs/trd.md authority must be reconciled non-destructively into this canonical foundation after it is stable rather than closing either PR or deleting valid work.

Exact-head evidence — 2026-09-20

  • protected base: main@1975f50ebe3da751097e015bdfa909ce80fc6ba2;
  • exact current head: 223228fd5ad8e37f6c5448ac6537dee9ae1c8598;
  • GitHub reports the PR open, Draft, and mechanically mergeable;
  • exact-head document-contracts, Security Scan, and SAST Semgrep are terminal GREEN;
  • exact-head CodeQL PR run 33889504891 is terminal cancelled, so the head is not fully settled;
  • there are zero live review threads and zero submitted reviews; qualifying independent approval remains absent;
  • the README contains one exact-cased ContextualWisdomLab DeepWiki badge and docs/index.md is a deterministic public landing source, but neither protected-main integration nor live Pages publication is claimed;
  • predecessor-head checks/reviews are not reused.

Merge gate

Keep Draft. Merge only through the ordinary protected path after the unchanged exact head has terminal required checks, fresh semantic review with no actionable finding, zero unresolved review threads, current base ancestry/mergeability, and the then-live governance requirements. No admin bypass, self-approval, force push, destructive rebase, or queued/pending/skipped evidence reuse is authorized.

@coderabbitai

coderabbitai Bot commented Aug 27, 2026 •

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@seonghobae seonghobae self-assigned this Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review the exact current head e8166dcf7b92b10fbff355f6f357967a0038865f, focusing on product-boundary consistency, bitemporal relationship truth, privacy/AI authority boundaries, OpenAPI/AsyncAPI coherence, and unsupported standards or research claims.

@seonghobae seonghobae removed their assignment Aug 27, 2026
@coderabbitai

coderabbitai Bot commented Aug 27, 2026 •

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

requested='e8166dcf7b92b10fbff355f6f357967a0038865f'
printf 'Checked-out HEAD: '
git rev-parse HEAD
printf 'Requested commit: %s\n\n' "$requested"

printf '%s\n' '--- tracked files ---'
git ls-tree -r --name-only "$requested"

printf '%s\n' '--- top-level structure ---'
fd -H -d 3 -t f . | sort

printf '%s\n' '--- candidate documents ---'
fd -H -t f -e md -e yaml -e yml -e json . | sort

Length of output: 5484


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- document headings and focused terms ---'
for f in \
  docs/ARCHITECTURE.md docs/DATA_MODEL.md docs/API_CONTRACT.md docs/PRIVACY.md \
  docs/PRD.md docs/TRD.md docs/doctoring/RESEARCH_BASIS.md \
  docs/doctoring/STANDARD_TRACEABILITY.md \
  docs/adr/0001-product-boundary.md docs/adr/0004-bitemporal-truth.md \
  docs/adr/0005-first-class-relationships.md docs/adr/0007-purpose-aware-privacy.md \
  docs/adr/0008-ai-human-judgment.md docs/adr/0016-cwl-ecosystem-boundaries.md; do
  echo "### $f"
  rg -n '^(#{1,4} )|(?i)\b(bitemporal|valid[_ -]?time|system[_ -]?time|relationship|truth|evidence|privacy|purpose|consent|AI|model|Keyverse|naruon|ThreadWeave|LineageWeave|RankWeave|orchestrator|TEPP|fast-mlsirm|ScopeWeave|Billing|RFC|ISO|NIST|OWASP|WCAG|GDPR|CCPA|research|study)\b' "$f" || true
done

printf '%s\n' '--- OpenAPI operations and component references ---'
python3 - <<'PY'
import yaml
p='schemas/openapi.yaml'
d=yaml.safe_load(open(p))
print('openapi:', d.get('openapi'))
for path, methods in d.get('paths',{}).items():
    for method, op in methods.items():
        if isinstance(op,dict) and method.lower() in {'get','put','post','patch','delete','head','options','trace'}:
            print(f'{method.upper()} {path} operationId={op.get("operationId")}')
            for code, r in op.get('responses',{}).items():
                print(f'  response {code}: {r.get("description")}')
print('schemas:', ', '.join(d.get('components',{}).get('schemas',{}).keys()))
PY

printf '%s\n' '--- AsyncAPI channels, operations, and message payload references ---'
python3 - <<'PY'
import yaml
p='schemas/asyncapi.yaml'
d=yaml.safe_load(open(p))
print('asyncapi:', d.get('asyncapi'))
for channel, item in d.get('channels',{}).items():
    print('channel:',channel)
    for k,v in item.items():
        if isinstance(v,dict):
            print(f'  {k}: operationId={v.get("operationId")} message={v.get("message")}')
print('messages:', ', '.join(d.get('components',{}).get('messages',{}).keys()))
PY

printf '%s\n' '--- event-schema fields and identifiers ---'
for f in schemas/events/*.json; do
  echo "### $f"
  python3 - "$f" <<'PY'
import json,sys
d=json.load(open(sys.argv[1]))
print('id:',d.get('$id'))
print('required:',d.get('required'))
for name, value in d.get('properties',{}).items():
    print(f'  {name}: type={value.get("type")} format={value.get("format")} ref={value.get("$ref")}')
PY
done

Length of output: 41310


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- bitemporal and relationship specifications ---'
for spec in \
  'docs/DATA_MODEL.md:170:255' \
  'docs/DATA_MODEL.md:439:510' \
  'docs/TRD.md:145:181' \
  'docs/API_CONTRACT.md:44:125' \
  'docs/API_CONTRACT.md:177:290' \
  'docs/adr/0004-bitemporal-truth.md:1:80' \
  'docs/adr/0005-first-class-relationships.md:1:80' \
  'docs/adr/0008-ai-human-judgment.md:1:80' \
  'docs/adr/0016-cwl-ecosystem-boundaries.md:1:80'; do
  file="${spec%%:*}"; remainder="${spec#*:}"; start="${remainder%%:*}"; end="${remainder##*:}"
  echo "### $file, lines $start-$end"
  sed -n "${start},${end}p" "$file" | nl -ba -v "$start"
done

printf '%s\n' '--- OpenAPI contract ---'
cat -n schemas/openapi.yaml

printf '%s\n' '--- AsyncAPI contract ---'
cat -n schemas/asyncapi.yaml

printf '%s\n' '--- JSON event contracts ---'
for f in schemas/events/*.json; do
  echo "### $f"
  jq '{schema: $schema, id: $id, title, type, required, properties, allOf, additionalProperties}' "$f"
done

printf '%s\n' '--- cross-contract relationship, event, and temporal references ---'
rg -n -i -C 2 '(relationship\.changed|opportunity\.stage\.changed|relationship-changed|opportunity-stage-changed|valid_time|recorded_time|truth_status|review_status|provenance|evidence_reference|model_claim)' \
  docs schemas .cwl README.md

Length of output: 1776


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show_range() {
  file="$1"
  start="$2"
  end="$3"
  echo "### $file, lines $start-$end"
  awk -v start="$start" -v end="$end" \
    'NR >= start && NR <= end { printf "%6d  %s\n", NR, $0 }' "$file"
}

printf '%s\n' '--- bitemporal, relationship, AI, and product-boundary specifications ---'
show_range docs/DATA_MODEL.md 170 255
show_range docs/DATA_MODEL.md 439 510
show_range docs/TRD.md 145 181
show_range docs/API_CONTRACT.md 44 125
show_range docs/API_CONTRACT.md 177 290
show_range docs/adr/0001-product-boundary.md 1 80
show_range docs/adr/0004-bitemporal-truth.md 1 80
show_range docs/adr/0005-first-class-relationships.md 1 80
show_range docs/adr/0007-purpose-aware-privacy.md 1 80
show_range docs/adr/0008-ai-human-judgment.md 1 80
show_range docs/adr/0016-cwl-ecosystem-boundaries.md 1 80

printf '%s\n' '--- OpenAPI contract ---'
awk '{ printf "%6d  %s\n", NR, $0 }' schemas/openapi.yaml

printf '%s\n' '--- AsyncAPI contract ---'
awk '{ printf "%6d  %s\n", NR, $0 }' schemas/asyncapi.yaml

printf '%s\n' '--- JSON event contracts ---'
for f in schemas/events/*.json; do
  echo "### $f"
  awk '{ printf "%6d  %s\n", NR, $0 }' "$f"
done

printf '%s\n' '--- reference bibliography and standards language ---'
awk '{ printf "%6d  %s\n", NR, $0 }' docs/doctoring/REFERENCES.md
awk '{ printf "%6d  %s\n", NR, $0 }' docs/doctoring/RESEARCH_BASIS.md
awk '{ printf "%6d  %s\n", NR, $0 }' docs/doctoring/STANDARD_TRACEABILITY.md

Length of output: 53432


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show_range() {
  file="$1"; start="$2"; end="$3"
  echo "### $file, lines $start-$end"
  awk -v start="$start" -v end="$end" \
    'NR >= start && NR <= end { printf "%6d  %s\n", NR, $0 }' "$file"
}

printf '%s\n' '--- omitted HTTP resource and temporal sections ---'
show_range docs/API_CONTRACT.md 1 43
show_range docs/API_CONTRACT.md 116 201
show_range docs/PRIVACY.md 1 145
show_range docs/TRD.md 205 290
show_range docs/ARCHITECTURE.md 30 50
show_range docs/ARCHITECTURE.md 130 177

printf '%s\n' '--- OpenAPI paths and temporal-parameter declarations ---'
rg -n -C 3 '(valid_at|recorded_at|knowledge_cutoff|/relationships|/model|/data-rights|/audit|/parties|/interactions|/commitments|/complaints|/search|X-Correlation|ETag|If-Match)' \
  schemas/openapi.yaml docs/API_CONTRACT.md

printf '%s\n' '--- authority, standards, and research assertions ---'
rg -n -i -C 2 '(authoritative|source.of.truth|source-of-truth|owns|retain.*authorit|ISO|NIST|OWASP|WCAG|PIPA|GDPR|certif|compli|proven|research|study|validated|calibrat)' \
  README.md docs .cwl SECURITY.md

Length of output: 124991


@seonghobae I reviewed commit e8166dcf7b92b10fbff355f6f357967a0038865f.

I found these contract issues:

  1. HTTP contract sources conflict.
    docs/API_CONTRACT.md declares schemas/openapi.yaml as the authoritative HTTP source. However, Line 123 through Line 197 list the P0 endpoints, while schemas/openapi.yaml defines only accounts, relationship creation, and opportunity-stage transitions. It also omits the required valid_at, recorded_at, and knowledge_cutoff parameters from Line 83.
    Generated SDKs and contract tests will not implement the stated HTTP contract. Define the listed operations and temporal parameters in OpenAPI, or reduce the narrative endpoint list to the actual OpenAPI surface.

  2. AsyncAPI reverses ELUNVERA’s event direction.
    Line 19 and Line 25 of schemas/asyncapi.yaml define receive operations named consumeRelationshipChanged and consumeOpportunityStageChanged. The architecture requires ELUNVERA to append and publish its domain events through the transactional outbox.
    AsyncAPI send is required for an ELUNVERA producer operation. Keep receive only if ELUNVERA also consumes these same channels.

  3. The AsyncAPI envelope omits required classification and schema metadata.
    docs/TRD.md Line 218 through Line 234 requires every domain event to include data_classification and schema_revision. CloudEventEnvelope in schemas/asyncapi.yaml Line 61 through Line 75 defines neither field.
    This omission prevents consumers from enforcing the stated minimum-data and privacy handling rules. It also prevents consumers from selecting the schema revision independently of the channel name. Add both fields with required constraints.

  4. The relationship event is not sufficient for bitemporal reconstruction.
    relationship-changed-v1.schema.json carries valid_from and valid_to, but it does not carry recorded_at or a recorded-time interval. The CloudEvents time field is not defined as system-recorded time. Outbox delay can make publication time differ from the time when ELUNVERA recorded the fact.
    Add an explicit recorded-time field, or define an unambiguous immutable recorded-time extension. This change is required to preserve the bitemporal contract in ADR-0004 and docs/TRD.md.

The source-of-truth boundary is internally consistent. The documents keep adjacent CWL systems authoritative for their defined domains. The privacy and AI rules also consistently prevent unreviewed model output from mutating CRM truth.

I found no unsupported implementation, certification, legal-compliance, or product-effectiveness claim in the reviewed standards and research material. The documents consistently mark these items as proposed, designed only, draft, or not implemented.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@seonghobae
seonghobae marked this pull request as draft August 27, 2026 13:26

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review the exact current head 3eab23a43038515850e34321a5de45b7e1422d93. The previous contract findings were addressed by aligning the narrative with the authoritative OpenAPI P0 surface, adding temporal request/response contracts, changing AsyncAPI operations to producer-side send, requiring classification/schema metadata, and adding explicit payload recorded_at. Please verify those fixes and check for any remaining product-boundary, bitemporal, privacy/AI authority, OpenAPI/AsyncAPI, standards, or research-traceability defects.

@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

requested='3eab23a43038515850e34321a5de45b7e1422d93'
actual="$(git rev-parse HEAD)"
printf 'HEAD=%s\nREQUESTED=%s\nMATCH=%s\n' "$actual" "$requested" "$([ "$actual" = "$requested" ] && echo yes || echo no)"

printf '\n--- Changed-file inventory at requested commit ---\n'
git ls-tree -r --name-only "$requested" | sort

printf '\n--- Candidate contract and authority documents ---\n'
fd -H -t f -e md -e yaml -e yml -e json . \
  | rg '(^|/)(API_CONTRACT|ARCHITECTURE|DATA_MODEL|PRIVACY|PRD|TRD|REFERENCES|RESEARCH_BASIS|STANDARD_TRACEABILITY)\.(md|yaml|yml|json)$|schemas/(openapi|asyncapi)\.yaml|schemas/events/|docs/adr/' \
  | sort

printf '\n--- API and temporal contract references ---\n'
rg -n -i -C 2 \
  '(authoritative.*OpenAPI|OpenAPI.*authoritative|P0|valid_at|recorded_at|knowledge_cutoff|X-Effective|temporal|operationId|idempotency|ETag|If-Match)' \
  docs schemas .cwl README.md 2>/dev/null || true

printf '\n--- Authority, relationship, privacy, AI, and standards assertions ---\n'
rg -n -i -C 2 \
  '(authoritative|source.of.truth|owns|retain.*authorit|relationship|truth_status|review_status|evidence|provenance|privacy|purpose|consent|model.claim|AI|automatic.*mutation|heuristic|ISO|NIST|OWASP|WCAG|GDPR|PIPA|certif|compli|validated|proven)' \
  docs README.md SECURITY.md .cwl 2>/dev/null || true

Length of output: 192504


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import json
from pathlib import Path
import yaml

def resolve_ref(root, ref):
    if not ref.startswith('`#/`'):
        return None
    node = root
    for part in ref[2:].split('/'):
        node = node[part]
    return node

def deref(root, node):
    seen = set()
    while isinstance(node, dict) and '$ref' in node:
        ref = node['$ref']
        if ref in seen:
            return node
        seen.add(ref)
        node = resolve_ref(root, ref)
        if node is None:
            return {'UNRESOLVED_REF': ref}
    return node

openapi = yaml.safe_load(Path('schemas/openapi.yaml').read_text())
print('--- OPENAPI ---')
print('version:', openapi.get('openapi'))
ops = []
for path, item in openapi.get('paths', {}).items():
    path_params = item.get('parameters', [])
    for method, operation in item.items():
        if method.lower() not in {'get','put','post','patch','delete','head','options','trace'}:
            continue
        merged = path_params + operation.get('parameters', [])
        params = []
        for param in merged:
            param = deref(openapi, param)
            params.append(f"{param.get('in')}:{param.get('name')}:{'required' if param.get('required') else 'optional'}")
        response_headers = {}
        for status, response in operation.get('responses', {}).items():
            response = deref(openapi, response)
            response_headers[status] = sorted(response.get('headers', {}).keys())
        ops.append((method.upper(), path, operation.get('operationId'), params, response_headers))
for op in ops:
    print(op)
print('unique operationIds:', len({x[2] for x in ops}) == len(ops))
print('unresolved refs:')
def refs(obj, location='$'):
    if isinstance(obj, dict):
        if '$ref' in obj:
            target = resolve_ref(openapi, obj['$ref'])
            if target is None:
                print(location, obj['$ref'])
        for k,v in obj.items(): refs(v, f'{location}/{k}')
    elif isinstance(obj, list):
        for i,v in enumerate(obj): refs(v, f'{location}[{i}]')
refs(openapi)

asyncapi = yaml.safe_load(Path('schemas/asyncapi.yaml').read_text())
print('\n--- ASYNCAPI ---')
print('version:', asyncapi.get('asyncapi'))
for key, operation in asyncapi.get('operations', {}).items():
    print('operation:', key, 'action=', operation.get('action'), 'channel=', operation.get('channel', {}).get('$ref'))
for channel, item in asyncapi.get('channels', {}).items():
    print('channel:', channel, 'messages=', item.get('messages'))
for name, schema in asyncapi.get('components', {}).get('schemas', {}).items():
    required = schema.get('required', [])
    props = schema.get('properties', {})
    if name.lower() in {'cloudeventenvelope', 'cloudevent'} or any(x in props for x in ('dataclassification','schemarevision')):
        print('schema:', name, 'required=', required, 'properties=', sorted(props))

print('\n--- EVENT PAYLOADS ---')
for p in sorted(Path('schemas/events').glob('*.json')):
    d=json.loads(p.read_text())
    print(p.name, 'draft=', d.get('$schema'), 'required=', d.get('required'), 'additionalProperties=', d.get('additionalProperties'))
    for field in ('recorded_at','valid_from','valid_to','truth_status','review_status','evidence_references'):
        if field in d.get('properties', {}):
            x=d['properties'][field]
            print(' ', field, 'type=',x.get('type'),'format=',x.get('format'),'const=',x.get('const'),'enum=',x.get('enum'))
PY

printf '\n--- Focused document and schema ranges ---\n'
for range in \
  'docs/API_CONTRACT.md:42:84' \
  'docs/API_CONTRACT.md:116:240' \
  'docs/adr/0004-bitemporal-truth.md:1:30' \
  'docs/adr/0016-cwl-ecosystem-boundaries.md:1:30' \
  'docs/doctoring/RESEARCH_BASIS.md:1:40' \
  'docs/doctoring/STANDARD_TRACEABILITY.md:1:30' \
  'schemas/openapi.yaml:1:360' \
  'schemas/asyncapi.yaml:1:260'; do
  file="${range%%:*}"; rest="${range#*:}"; start="${rest%%:*}"; end="${rest##*:}"
  printf '\n### %s, Lines %s-%s\n' "$file" "$start" "$end"
  sed -n "${start},${end}p" "$file" | nl -ba -v "$start"
done

printf '\n--- Validate JSON Schema Draft 2020-12 payloads against their meta-schema when jsonschema is available ---\n'
python3 - <<'PY'
try:
    import json
    from pathlib import Path
    from jsonschema import Draft202012Validator
    for p in sorted(Path('schemas/events').glob('*.json')):
        Draft202012Validator.check_schema(json.loads(p.read_text()))
        print(f'{p}: valid meta-schema')
except ModuleNotFoundError:
    print('jsonschema module unavailable; skipped')
PY

Length of output: 5021


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 -m pip install --quiet --target /tmp/elunvera-review-python PyYAML jsonschema

PYTHONPATH=/tmp/elunvera-review-python python3 - <<'PY'
import json
from pathlib import Path
import yaml
from jsonschema import Draft202012Validator

def local_ref(root, ref):
    if not ref.startswith('`#/`'):
        return None
    node = root
    for part in ref[2:].split('/'):
        node = node[part]
    return node

def deref(root, node):
    while isinstance(node, dict) and '$ref' in node:
        node = local_ref(root, node['$ref'])
        if node is None:
            return {}
    return node

openapi = yaml.safe_load(Path('schemas/openapi.yaml').read_text())
print('--- OPENAPI ---')
print('version=', openapi.get('openapi'))
operations = []
for path, path_item in openapi.get('paths', {}).items():
    for method, operation in path_item.items():
        if method.lower() not in {'get','put','post','patch','delete','head','options','trace'}:
            continue
        params = path_item.get('parameters', []) + operation.get('parameters', [])
        params = [deref(openapi, p) for p in params]
        response_headers = {
            status: sorted(deref(openapi, response).get('headers', {}).keys())
            for status, response in operation.get('responses', {}).items()
        }
        operations.append({
            'method': method.upper(), 'path': path,
            'operation_id': operation.get('operationId'),
            'parameters': [f"{p.get('in')}:{p.get('name')}:{p.get('required', False)}" for p in params],
            'response_headers': response_headers
        })
print(json.dumps(operations, indent=2))
ids = [x['operation_id'] for x in operations]
print('operation_ids_unique=', len(ids) == len(set(ids)))
print('operation_ids_complete=', all(ids))

asyncapi = yaml.safe_load(Path('schemas/asyncapi.yaml').read_text())
print('--- ASYNCAPI ---')
print('version=', asyncapi.get('asyncapi'))
print('operations=', json.dumps({
    name: {'action': value.get('action'), 'channel': value.get('channel', {}).get('$ref')}
    for name, value in asyncapi.get('operations', {}).items()
}, indent=2))
for name, value in asyncapi.get('components', {}).get('schemas', {}).items():
    if name == 'CloudEventEnvelope':
        print('CloudEventEnvelope.required=', value.get('required'))
        print('CloudEventEnvelope.properties=', sorted(value.get('properties', {})))
print('messages=', sorted(asyncapi.get('components', {}).get('messages', {})))

print('--- EVENT SCHEMAS ---')
for p in sorted(Path('schemas/events').glob('*.json')):
    data = json.loads(p.read_text())
    Draft202012Validator.check_schema(data)
    print(p.name)
    print(' required=', data.get('required'))
    print(' properties=', sorted(data.get('properties', {})))
    print(' additionalProperties=', data.get('additionalProperties'))
PY

printf '\n--- Exact source sections ---\n'
for entry in \
  'schemas/openapi.yaml:1:360' \
  'schemas/asyncapi.yaml:1:260' \
  'schemas/events/relationship-changed-v1.schema.json:1:240' \
  'schemas/events/opportunity-stage-changed-v1.schema.json:1:220' \
  'docs/API_CONTRACT.md:42:240' \
  'docs/adr/0004-bitemporal-truth.md:1:30' \
  'docs/adr/0016-cwl-ecosystem-boundaries.md:1:30'; do
  file="${entry%%:*}"; rest="${entry#*:}"; start="${rest%%:*}"; end="${rest##*:}"
  printf '\n### %s, Lines %s-%s\n' "$file" "$start" "$end"
  sed -n "${start},${end}p" "$file" | nl -ba -v "$start"
done

Length of output: 3815


🏁 Script executed:

#!/bin/bash
set -u

printf '%s\n' '--- Available YAML tooling ---'
command -v ruby || true
command -v yq || true
command -v perl || true

if command -v ruby >/dev/null 2>&1; then
  ruby -ryaml -rjson - <<'RUBY' || true
openapi = YAML.load_file('schemas/openapi.yaml')
puts '--- OPENAPI STRUCTURE ---'
puts "version=#{openapi['openapi']}"
operations = []
(openapi['paths'] || {}).each do |path, path_item|
  path_item.each do |method, op|
    next unless %w[get put post patch delete head options trace].include?(method)
    params = (path_item['parameters'] || []) + (op['parameters'] || [])
    params = params.map do |param|
      if param['$ref']
        openapi.dig(*param['$ref'].sub('`#/`', '').split('/'))
      else
        param
      end
    end
    headers = (op['responses'] || {}).transform_values do |response|
      response = openapi.dig(*response['$ref'].sub('`#/`', '').split('/')) if response['$ref']
      (response['headers'] || {}).keys.sort
    end
    operations << [method.upcase, path, op['operationId'], params.map { |p| "#{p['in']}:#{p['name']}:#{p['required'] == true}" }, headers]
  end
end
puts JSON.pretty_generate(operations)
ids = operations.map { |x| x[2] }
puts "unique_operation_ids=#{ids.compact.uniq.size == ids.size}"

asyncapi = YAML.load_file('schemas/asyncapi.yaml')
puts '--- ASYNCAPI STRUCTURE ---'
puts "version=#{asyncapi['asyncapi']}"
(asyncapi['operations'] || {}).each { |name, op| puts "#{name}: action=#{op['action']} channel=#{op.dig('channel', '$ref')}" }
envelope = asyncapi.dig('components', 'schemas', 'CloudEventEnvelope') || {}
puts "envelope_required=#{envelope['required']}"
puts "envelope_properties=#{(envelope['properties'] || {}).keys.sort}"

puts '--- EVENT JSON STRUCTURE ---'
Dir['schemas/events/*.json'].sort.each do |file|
  schema = JSON.parse(File.read(file))
  puts "#{file}: required=#{schema['required']} properties=#{schema.fetch('properties', {}).keys.sort} additionalProperties=#{schema['additionalProperties']}"
end
RUBY
fi

printf '\n%s\n' '--- OpenAPI exact content ---'
cat -n schemas/openapi.yaml
printf '\n%s\n' '--- AsyncAPI exact content ---'
cat -n schemas/asyncapi.yaml
printf '\n%s\n' '--- Relationship event exact content ---'
cat -n schemas/events/relationship-changed-v1.schema.json
printf '\n%s\n' '--- Opportunity event exact content ---'
cat -n schemas/events/opportunity-stage-changed-v1.schema.json

printf '\n%s\n' '--- Focused cross-contract text ---'
for entry in \
  'docs/API_CONTRACT.md:42:240' \
  'docs/adr/0004-bitemporal-truth.md:1:30' \
  'docs/adr/0016-cwl-ecosystem-boundaries.md:1:30' \
  'docs/PRIVACY.md:1:180' \
  'docs/doctoring/RESEARCH_BASIS.md:1:40' \
  'docs/doctoring/STANDARD_TRACEABILITY.md:1:30'; do
  file="${entry%%:*}"; rest="${entry#*:}"; start="${rest%%:*}"; end="${rest##*:}"
  printf '\n### %s, Lines %s-%s\n' "$file" "$start" "$end"
  sed -n "${start},${end}p" "$file" | nl -ba -v "$start"
done

printf '\n%s\n' '--- JSON syntax validation ---'
for file in schemas/events/*.json; do
  printf '%s: ' "$file"
  python3 -m json.tool "$file" >/dev/null && echo valid
done

Length of output: 32691


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show_range() {
  file="$1"; start="$2"; end="$3"
  printf '\n### %s, Lines %s-%s\n' "$file" "$start" "$end"
  awk -v start="$start" -v end="$end" \
    'NR >= start && NR <= end { printf "%d  %s\n", NR, $0 }' "$file"
}

show_range docs/API_CONTRACT.md 1 240
show_range docs/PRIVACY.md 1 220
show_range docs/ARCHITECTURE.md 30 250
show_range docs/DATA_MODEL.md 174 260
show_range docs/DATA_MODEL.md 409 455
show_range docs/adr/0004-bitemporal-truth.md 1 30
show_range docs/adr/0008-ai-human-judgment.md 1 30
show_range docs/adr/0016-cwl-ecosystem-boundaries.md 1 35
show_range docs/doctoring/RESEARCH_BASIS.md 1 35
show_range docs/doctoring/STANDARD_TRACEABILITY.md 1 25

ruby -ryaml -rjson - <<'RUBY'
require 'pathname'

def resolve_local_ref(root, ref)
  return nil unless ref.start_with?('`#/`')
  ref.sub('`#/`', '').split('/').reduce(root) { |node, key| node.is_a?(Hash) ? node[key] : nil }
end

openapi = YAML.load_file('schemas/openapi.yaml')
asyncapi = YAML.load_file('schemas/asyncapi.yaml')
errors = []

openapi.fetch('paths', {}).each do |path, item|
  item.each do |method, operation|
    next unless %w[get post put patch delete head options trace].include?(method)
    (item.fetch('parameters', []) + operation.fetch('parameters', [])).each do |param|
      if param['$ref'] && resolve_local_ref(openapi, param['$ref']).nil?
        errors << "OpenAPI unresolved parameter ref #{param['$ref']} at #{method.upcase} #{path}"
      end
    end
  end
end

asyncapi.fetch('components', {}).fetch('messages', {}).each do |name, message|
  payload = message['payload'] || {}
  (payload['allOf'] || []).each do |part|
    if part['$ref']&.start_with?('./')
      target = File.expand_path(part['$ref'], 'schemas')
      errors << "AsyncAPI missing payload #{target}" unless File.file?(target)
    end
    if part.dig('properties', 'data', '$ref')&.start_with?('./')
      target = File.expand_path(part.dig('properties', 'data', '$ref'), 'schemas')
      errors << "AsyncAPI missing data schema #{target}" unless File.file?(target)
    end
  end
end

expected = {
  'RelationshipChanged' => 'org.contextualwisdomlab.elunvera.relationship.changed.v1',
  'OpportunityStageChanged' => 'org.contextualwisdomlab.elunvera.opportunity.stage_changed.v1'
}
expected.each do |message, type|
  actual = asyncapi.dig('components', 'messages', message, 'payload', 'allOf', 1, 'properties', 'type', 'const')
  errors << "AsyncAPI type mismatch for #{message}: #{actual.inspect}" unless actual == type
end

puts "\n--- Contract reference and message-binding checks ---"
puts(errors.empty? ? 'PASS' : errors.join("\n"))
RUBY

python3 - <<'PY'
from pathlib import Path
import re

root = Path('.').resolve()
errors = []
for path in Path('docs').rglob('*.md'):
    text = path.read_text(encoding='utf-8')
    for target in re.findall(r'\[[^\]]*\]\(([^)#\s]+)(?:#[^)]+)?\)', text):
        if '://' in target or target.startswith('mailto:'):
            continue
        resolved = (path.parent / target).resolve()
        if root not in resolved.parents and resolved != root:
            errors.append(f'{path}: link escapes repository: {target}')
        elif not resolved.exists():
            errors.append(f'{path}: missing target: {target}')
print('\n--- Markdown relative-link checks ---')
print('PASS' if not errors else '\n'.join(errors))
PY

printf '\n--- Unsupported-claim keyword scan with context ---\n'
rg -n -i -C 1 \
  '\b(certified|certification|compliant|compliance|conform|proven|validated|guarantee[sd]?|improves?|effective|secure|production-ready)\b' \
  README.md docs SECURITY.md 2>/dev/null || true

Length of output: 57254


@seonghobae I reviewed commit 3eab23a43038515850e34321a5de45b7e1422d93.

The four prior findings are resolved:

  • The OpenAPI P0 operations match docs/API_CONTRACT.md.
  • Both account read operations define valid_at, recorded_at, and knowledge_cutoff. They return the effective temporal-lens headers.
  • AsyncAPI defines ELUNVERA producer operations with action: send.
  • The CloudEvent envelope requires dataclassification and schemarevision.
  • Both event payload schemas require explicit recorded_at.
  • The contract-reference and Markdown-link checks passed.

I found one remaining contract issue:

  1. AsyncAPI permits events without provenance.
    docs/ARCHITECTURE.md Line 248 requires every event to have provenance. docs/TRD.md also lists provenanceref as required event metadata. However, schemas/asyncapi.yaml Line 108 defines provenanceref as optional, and Line 61 through Line 74 does not include it in CloudEventEnvelope.required.
    A producer can therefore emit a valid contract event without provenance. Require provenanceref in CloudEventEnvelope, or revise the architecture and TRD statements to define the limited cases where provenance is absent.

The product ownership boundary remains consistent. The privacy and AI documents keep model claims separate from authoritative CRM facts. The research and standards documents state design traceability only. I found no unsupported certification, legal-compliance, implementation, or effectiveness claim.

You are interacting with an AI system.

Copy link
Copy Markdown
Contributor Author

Exact-head public-surface reconciliation — 2026-09-20

  • source head remains 223228fd5ad8e37f6c5448ac6537dee9ae1c8598; no source commit was added
  • README exact linked DeepWiki badge count: 1
  • docs/index.md exists and retains bounded responsibility plus the explicit no-publication-before-live-verification statement
  • changed-file inventory already includes both README.md and docs/index.md
  • mergeability: true; lifecycle: Draft
  • exact-head checks: document-contracts, Security Scan, and SAST Semgrep GREEN; CodeQL PR run 33889504891 cancelled
  • review threads: 0; submitted reviews: 0
  • canonical labels normalized to documentation / priority: medium / status: draft; conflicting type: docs alias removed

Central desired-state enrollment is TDD-backed in ContextualWisdomLab/.github#2110: RED 23f39cddfe91ebdf9adbb824b87479e57565196a, implementation 5fb40adf247ee8a2748ed10da81011e1353f9050. Protected-main integration, live repository settings, and GitHub Pages HTTP publication remain unproven and are not claimed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation priority: medium status: draft

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant