diff --git a/.github/workflows/product.yml b/.github/workflows/product.yml index 8700247d..873457ef 100644 --- a/.github/workflows/product.yml +++ b/.github/workflows/product.yml @@ -2,7 +2,7 @@ name: Product on: pull_request: - types: [opened, synchronize, reopened, ready_for_review, converted_to_draft, closed] + types: [opened, synchronize, reopened, ready_for_review] push: branches: [main] @@ -15,7 +15,6 @@ permissions: jobs: rust-quality: - if: ${{ github.event_name != 'pull_request' || (github.event.action != 'closed' && github.event.pull_request.draft == false) }} runs-on: ubuntu-24.04 env: COVERAGE_TOOLCHAIN: nightly-2026-08-20 @@ -63,37 +62,18 @@ jobs: - name: Exact owned coverage run: ./scripts/check_coverage.sh - - name: Validate public JSON contract - run: | - npx --yes ajv-cli@5.0.0 compile \ - --spec=draft2020 \ - -s contracts/semantic-candidate.schema.json - npx --yes ajv-cli@5.0.0 test \ - --spec=draft2020 \ - -s contracts/semantic-candidate.schema.json \ - -d contracts/fixtures/semantic-candidate.valid.json \ - --valid - npx --yes ajv-cli@5.0.0 test \ - --spec=draft2020 \ - -s contracts/semantic-candidate.schema.json \ - -d contracts/fixtures/semantic-candidate.invalid-whitespace.json \ - --invalid - npx --yes ajv-cli@5.0.0 test \ - --spec=draft2020 \ - -s contracts/semantic-candidate.schema.json \ - -d contracts/fixtures/semantic-candidate.invalid-published-truth.json \ - --invalid - npx --yes ajv-cli@5.0.0 test \ - --spec=draft2020 \ - -s contracts/semantic-candidate.schema.json \ - -d contracts/fixtures/semantic-candidate.invalid-state-truth-mismatch.json \ - --invalid + - name: Install pinned JSON Schema validator + run: npm ci --ignore-scripts --no-audit --no-fund + + - name: Validate public JSON contracts + run: npm run check:json-contracts - name: Lockfile freshness run: | cargo generate-lockfile --locked git ls-files --error-unmatch Cargo.lock >/dev/null - test -z "$(git status --porcelain=v1 --untracked-files=all -- Cargo.lock)" + git ls-files --error-unmatch package-lock.json >/dev/null + test -z "$(git status --porcelain=v1 --untracked-files=all -- Cargo.lock package-lock.json)" - name: Clean working tree run: test -z "$(git status --porcelain=v1 --untracked-files=all)" diff --git a/.gitignore b/.gitignore index c11a1dfc..0c56bcc5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /target +/node_modules *.profraw coverage.json .DS_Store diff --git a/AGENTS.md b/AGENTS.md index 67347566..220e8c5d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,3 +21,12 @@ ConceptWeave owns automatic, evidence-bound **Semantic Model Engineering**. Do n - Owned production coverage target is 100% line/function/region/branch where tooling exposes it. - Never suppress deprecation warnings; fix causes. - Never force-push shared branches, self-approve, fabricate checks, or weaken branch protection. + +## Procedural model engineering (Proposed, issue #42) + +Follow [ADR-PG-20260910](docs/adr/pg_20260910_procedural_model_engineering.md). +ConceptWeave owns evidence-bound procedural authoring, semantic validation and model +publication; Noema owns execution-local guidance/lifecycle. The local draft schemas +and their shape tests grant no publication, runtime or tool authority. Preserve the +existing candidate schema and Noema implementation. Rust semantic validation and +released cross-product contracts must precede any runtime integration. diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index c5dd4993..adb28e87 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -75,3 +75,14 @@ scripts/ # Deterministic repository-quality helpers ``` Adapters and application services are added only when their bounded responsibility exists; generic `utils`, `helpers`, or `services` dumping grounds are prohibited. + +## Procedural knowledge profile — Proposed + +The existing discovery/validation/publication contexts also own procedure concepts, +advisory relations, evidence alignment and reviewed model revisions. Noema consumes +a released projection for online advice and retains execution/cancellation authority. +CO supplies model calls; CGC owns shared interchange; SDP catalogs releases; EAC owns +the architecture/adoption map. Product factual and policy authority do not move. +See [ADR-PG-20260910](docs/adr/pg_20260910_procedural_model_engineering.md) for the +context/aggregate map, UML, source claims, current input-schema implementation and +explicit Rust, governance, projection, security and recovery prerequisites. diff --git a/CHANGELOG.md b/CHANGELOG.md index 8910d6fa..80fe0ddb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ All notable changes to ConceptWeave are documented here. ### Added +- Proposed procedural-model engineering profile: local draft/revision input schemas, structural conformance fixtures and existing Product AJV wiring. ConceptWeave owns authoring/validation/publication; Noema retains runtime guidance. No Rust semantic validator, model call, release or activation is delivered by this input-contract slice. Issue #42; ADR-PG-20260910. + - Initial ConceptWeave product, DDD, security, test, and operability baselines. - Rust 1.98.0 `conceptweave-domain` foundation with evidence-bound semantic candidate contracts. - Fail-closed Draft -> Proposed -> Validated -> Reviewed -> Published lifecycle with explicit rejection and supersession. diff --git a/CLAUDE.md b/CLAUDE.md index d8db2650..17348c64 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,3 +5,9 @@ Follow `AGENTS.md`, `ARCHITECTURE.md`, accepted ADRs, and the organization maste ConceptWeave's core invariant is: **inference is not authority**. Every generated concept, relation, constraint, dimension, measure, or physical mapping must retain evidence and pass the explicit governance lifecycle before publication. Keep domain logic in bounded domain modules, LLM/provider logic behind ports/adapters, and source/consumer systems independent. Prefer deterministic validation and explicit abstention over plausible unsupported output. + +For procedural knowledge, apply the same inference/authority separation through +[ADR-PG-20260910](docs/adr/pg_20260910_procedural_model_engineering.md) and issue #42. +Do not turn a shape-valid authoring draft, training-partition label, or digest string +into authenticated evidence. Noema's execution-local projection is not a competing +ConceptWeave publisher, and this schema slice is not a deployed self-evolving agent. diff --git a/contracts/fixtures/procedural-authoring.cases.json b/contracts/fixtures/procedural-authoring.cases.json new file mode 100644 index 00000000..f4204201 --- /dev/null +++ b/contracts/fixtures/procedural-authoring.cases.json @@ -0,0 +1,52 @@ +{ + "validation_scope": "input_shape_only", + "fixture_data_policy": "synthetic_unit_test_only", + "case_rows": [ + {"case_name":"valid_inferred_model","base_name":"model","shape_valid":true,"semantic_expectation":"not_evaluated","changes":[]}, + {"case_name":"valid_training_revision","base_name":"revision","shape_valid":true,"semantic_expectation":"not_evaluated","changes":[]}, + {"case_name":"valid_empty_transition_skeleton","base_name":"model","shape_valid":true,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_edges"],"field_value":[]}]}, + {"case_name":"valid_eight_locale_labels","base_name":"model","shape_valid":true,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_nodes",0,"locale_labels"],"field_value":{"ko":"Unit fixture label","en":"Unit fixture label","ja":"Unit fixture label","zh":"Unit fixture label","vi":"Unit fixture label","es":"Unit fixture label","de":"Unit fixture label","fr":"Unit fixture label"}}]}, + {"case_name":"valid_requires_advisory_relation","base_name":"model","shape_valid":true,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_edges",0,"relation_type"],"field_value":"requires"}]}, + {"case_name":"valid_enables_advisory_relation","base_name":"model","shape_valid":true,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_edges",0,"relation_type"],"field_value":"enables"}]}, + {"case_name":"valid_skill_procedure","base_name":"model","shape_valid":true,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_nodes",0,"procedure_kind"],"field_value":"skill_procedure"}]}, + {"case_name":"valid_task_state","base_name":"model","shape_valid":true,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_nodes",0,"procedure_kind"],"field_value":"task_state"}]}, + {"case_name":"valid_steward_revision","base_name":"revision","shape_valid":true,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["proposal_origin"],"field_value":"steward_authored"}]}, + {"case_name":"reject_published_state","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["publication_state"],"field_value":"published"}]}, + {"case_name":"reject_authoritative_truth","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["truth_status"],"field_value":"authoritative"}]}, + {"case_name":"reject_inferred_promotion_flag","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["activation_authorized"],"field_value":true}]}, + {"case_name":"reject_missing_source_set","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["source_evidence"],"field_value":[]}]}, + {"case_name":"reject_blank_source_location","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["source_evidence",0,"location"],"field_value":" "}]}, + {"case_name":"reject_mutable_source_digest","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["source_evidence",0,"source_digest"],"field_value":"main"}]}, + {"case_name":"reject_uppercase_digest","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["source_evidence",0,"source_digest"],"field_value":"sha256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}]}, + {"case_name":"reject_node_without_evidence","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_nodes",0,"source_evidence"],"field_value":[]}]}, + {"case_name":"reject_duplicate_node_record","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_nodes"],"field_value":[{"procedure_id":"read_review","procedure_kind":"reasoning_step","locale_labels":{"ko":"리뷰 근거 읽기","en":"Read review evidence"},"source_evidence":[{"source_id":"unit_fixture_review_sop","source_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","location":"section_2/step_1"}]},{"procedure_id":"read_review","procedure_kind":"reasoning_step","locale_labels":{"ko":"리뷰 근거 읽기","en":"Read review evidence"},"source_evidence":[{"source_id":"unit_fixture_review_sop","source_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","location":"section_2/step_1"}]}]}]}, + {"case_name":"reject_duplicate_edge_record","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_edges"],"field_value":[{"source_procedure_id":"read_review","relation_type":"leads_to","target_procedure_id":"verify_finding","condition":{"ko":"검토할 근거가 있습니다.","en":"Evidence is available for review."},"guidance":{"ko":"현재 수정본에서 지적 사항을 재현합니다.","en":"Reproduce the finding against the current revision."},"pitfalls":{"ko":"이전 수정본의 통과 기록을 승인 근거로 사용하지 않습니다.","en":"Do not treat an older revision result as approval."},"source_evidence":[{"source_id":"unit_fixture_review_sop","source_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","location":"section_2/step_1"}]},{"source_procedure_id":"read_review","relation_type":"leads_to","target_procedure_id":"verify_finding","condition":{"ko":"검토할 근거가 있습니다.","en":"Evidence is available for review."},"guidance":{"ko":"현재 수정본에서 지적 사항을 재현합니다.","en":"Reproduce the finding against the current revision."},"pitfalls":{"ko":"이전 수정본의 통과 기록을 승인 근거로 사용하지 않습니다.","en":"Do not treat an older revision result as approval."},"source_evidence":[{"source_id":"unit_fixture_review_sop","source_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","location":"section_2/step_1"}]}]}]}, + {"case_name":"reject_empty_node_set","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_nodes"],"field_value":[]}]}, + {"case_name":"reject_empty_identifier","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_nodes",0,"procedure_id"],"field_value":""}]}, + {"case_name":"reject_whitespace_identifier","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["entry_procedure_id"],"field_value":"read_review\n"}]}, + {"case_name":"reject_unknown_procedure_kind","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_nodes",0,"procedure_kind"],"field_value":"authorization"}]}, + {"case_name":"reject_permission_relation","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_edges",0,"relation_type"],"field_value":"grants_permission"}]}, + {"case_name":"reject_edge_execute_field","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_edges",0,"execute"],"field_value":true}]}, + {"case_name":"reject_missing_guidance","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"remove","field_path":["procedure_edges",0,"guidance"]}]}, + {"case_name":"reject_blank_guidance","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_edges",0,"guidance"],"field_value":{"en":" "}}]}, + {"case_name":"reject_invalid_locale_value","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_nodes",0,"locale_labels","ko"],"field_value":4}]}, + {"case_name":"reject_unsupported_locale","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_nodes",0,"locale_labels"],"field_value":{"xx":"Test"}}]}, + {"case_name":"reject_empty_labels","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_nodes",0,"locale_labels"],"field_value":{}}]}, + {"case_name":"reject_tool_without_contract","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"remove","field_path":["procedure_nodes",1,"tool_contract_ref"]}]}, + {"case_name":"reject_tool_trailing_newline_digest","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_nodes",1,"tool_contract_ref","artifact_digest"],"field_value":"sha256:2222222222222222222222222222222222222222222222222222222222222222\n"}]}, + {"case_name":"reject_inline_foreign_truth","base_name":"model","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["procedure_nodes",0,"semantic_refs"],"field_value":[{"authority_ref":"ContextualWisdomLab/Orgmetra","release_ref":"unit_fixture_release","artifact_digest":"sha256:4444444444444444444444444444444444444444444444444444444444444444","object_ref":"job_concept","employee_table":[]}]}]}, + {"case_name":"reject_revision_holdout_partition","base_name":"revision","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["evidence_partition"],"field_value":"holdout"}]}, + {"case_name":"reject_revision_self_approval","base_name":"revision","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["decision_authority"],"field_value":"approved"}]}, + {"case_name":"reject_revision_published_state","base_name":"revision","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["proposal_state"],"field_value":"published"}]}, + {"case_name":"reject_revision_holdout_scores","base_name":"revision","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["validation_scores"],"field_value":[1.0]}]}, + {"case_name":"reject_revision_raw_trajectory","base_name":"revision","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["raw_trajectory"],"field_value":"private content"}]}, + {"case_name":"reject_revision_no_training_evidence","base_name":"revision","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["training_evidence"],"field_value":[]}]}, + {"case_name":"reject_revision_stale_label_digest","base_name":"revision","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["base_model_ref","artifact_digest"],"field_value":"main"}]}, + {"case_name":"reject_revision_nested_authority","base_name":"revision","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["candidate_model","truth_status"],"field_value":"authoritative"}]}, + {"case_name":"reject_revision_blank_rationale","base_name":"revision","shape_valid":false,"semantic_expectation":"not_evaluated","changes":[{"operation":"set","field_path":["change_rationale"],"field_value":" "}]}, + {"case_name":"known_gap_dangling_endpoint","base_name":"model","shape_valid":true,"semantic_expectation":"must_reject_dangling_endpoint","changes":[{"operation":"set","field_path":["procedure_edges",0,"target_procedure_id"],"field_value":"absent_node"}]}, + {"case_name":"known_gap_missing_entry","base_name":"model","shape_valid":true,"semantic_expectation":"must_reject_missing_entry","changes":[{"operation":"set","field_path":["entry_procedure_id"],"field_value":"absent_entry"}]}, + {"case_name":"known_gap_same_node_id_different_record","base_name":"model","shape_valid":true,"semantic_expectation":"must_reject_duplicate_identity","changes":[{"operation":"set","field_path":["procedure_nodes",1,"procedure_id"],"field_value":"read_review"}]}, + {"case_name":"known_gap_scope_evidence_authenticity","base_name":"revision","shape_valid":true,"semantic_expectation":"requires_authenticated_evidence_and_exact_base_scope","changes":[]} + ] +} diff --git a/contracts/fixtures/procedural-model.base.json b/contracts/fixtures/procedural-model.base.json new file mode 100644 index 00000000..e7de0ccc --- /dev/null +++ b/contracts/fixtures/procedural-model.base.json @@ -0,0 +1 @@ +{"schema_version":"0.1.0-draft.1","model_id":"review_procedure_model","tenant_ref":"unit_fixture_tenant","task_type":"review_repair","domain_owner_ref":"ContextualWisdomLab/.github","publication_state":"draft","truth_status":"inferred","entry_procedure_id":"read_review","source_evidence":[{"source_id":"unit_fixture_review_sop","source_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","location":"section_2/step_1"}],"procedure_nodes":[{"procedure_id":"read_review","procedure_kind":"reasoning_step","locale_labels":{"ko":"리뷰 근거 읽기","en":"Read review evidence"},"source_evidence":[{"source_id":"unit_fixture_review_sop","source_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","location":"section_2/step_1"}]},{"procedure_id":"verify_finding","procedure_kind":"tool_operation","locale_labels":{"ko":"지적 사항 검증","en":"Verify the finding"},"source_evidence":[{"source_id":"unit_fixture_review_sop","source_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","location":"section_2/step_1"}],"tool_contract_ref":{"authority_ref":"ContextualWisdomLab/noema","release_ref":"unit_fixture_release","artifact_digest":"sha256:2222222222222222222222222222222222222222222222222222222222222222","object_ref":"verify_evidence"}}],"procedure_edges":[{"source_procedure_id":"read_review","relation_type":"leads_to","target_procedure_id":"verify_finding","condition":{"ko":"검토할 근거가 있습니다.","en":"Evidence is available for review."},"guidance":{"ko":"현재 수정본에서 지적 사항을 재현합니다.","en":"Reproduce the finding against the current revision."},"pitfalls":{"ko":"이전 수정본의 통과 기록을 승인 근거로 사용하지 않습니다.","en":"Do not treat an older revision result as approval."},"source_evidence":[{"source_id":"unit_fixture_review_sop","source_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","location":"section_2/step_1"}]}]} diff --git a/contracts/fixtures/procedural-revision.base.json b/contracts/fixtures/procedural-revision.base.json new file mode 100644 index 00000000..9e0d96aa --- /dev/null +++ b/contracts/fixtures/procedural-revision.base.json @@ -0,0 +1 @@ +{"schema_version":"0.1.0-draft.1","proposal_id":"review_revision_proposal","proposal_origin":"model_assisted","proposal_state":"proposed","decision_authority":"none","base_model_ref":{"authority_ref":"ContextualWisdomLab/ConceptWeave","release_ref":"unit_fixture_base","artifact_digest":"sha256:3333333333333333333333333333333333333333333333333333333333333333","object_ref":"review_procedure_model"},"candidate_model":{"schema_version":"0.1.0-draft.1","model_id":"review_procedure_model","tenant_ref":"unit_fixture_tenant","task_type":"review_repair","domain_owner_ref":"ContextualWisdomLab/.github","publication_state":"draft","truth_status":"inferred","entry_procedure_id":"read_review","source_evidence":[{"source_id":"unit_fixture_review_sop","source_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","location":"section_2/step_1"}],"procedure_nodes":[{"procedure_id":"read_review","procedure_kind":"reasoning_step","locale_labels":{"ko":"리뷰 근거 읽기","en":"Read review evidence"},"source_evidence":[{"source_id":"unit_fixture_review_sop","source_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","location":"section_2/step_1"}]},{"procedure_id":"verify_finding","procedure_kind":"tool_operation","locale_labels":{"ko":"지적 사항 검증","en":"Verify the finding"},"source_evidence":[{"source_id":"unit_fixture_review_sop","source_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","location":"section_2/step_1"}],"tool_contract_ref":{"authority_ref":"ContextualWisdomLab/noema","release_ref":"unit_fixture_release","artifact_digest":"sha256:2222222222222222222222222222222222222222222222222222222222222222","object_ref":"verify_evidence"}}],"procedure_edges":[{"source_procedure_id":"read_review","relation_type":"leads_to","target_procedure_id":"verify_finding","condition":{"ko":"검토할 근거가 있습니다.","en":"Evidence is available for review."},"guidance":{"ko":"현재 수정본에서 지적 사항을 재현합니다.","en":"Reproduce the finding against the current revision."},"pitfalls":{"ko":"이전 수정본의 통과 기록을 승인 근거로 사용하지 않습니다.","en":"Do not treat an older revision result as approval."},"source_evidence":[{"source_id":"unit_fixture_review_sop","source_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","location":"section_2/step_1"}]}]},"evidence_partition":"training","training_evidence":[{"source_id":"unit_fixture_review_sop","source_digest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","location":"section_2/step_1"}],"rejected_edit_refs":[],"change_rationale":"Unit fixture only: make exact-revision verification explicit before suggesting a repair."} diff --git a/contracts/procedural-model-draft.schema.json b/contracts/procedural-model-draft.schema.json new file mode 100644 index 00000000..31193713 --- /dev/null +++ b/contracts/procedural-model-draft.schema.json @@ -0,0 +1 @@ +{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"urn:cwl:conceptweave:procedural-model-draft:v0.1.0-draft.1","title":"ConceptWeave procedural model authoring draft","description":"Local unreleased candidate input, not the Noema runtime or a published CWL interchange contract. Shape conformance never establishes graph integrity, authenticated evidence, approval or execution authority.","type":"object","additionalProperties":false,"required":["schema_version","model_id","tenant_ref","task_type","domain_owner_ref","publication_state","truth_status","entry_procedure_id","source_evidence","procedure_nodes","procedure_edges"],"properties":{"schema_version":{"const":"0.1.0-draft.1"},"model_id":{"$ref":"#/$defs/identity_text"},"tenant_ref":{"$ref":"#/$defs/identity_text"},"task_type":{"$ref":"#/$defs/identity_text"},"domain_owner_ref":{"$ref":"#/$defs/identity_text"},"publication_state":{"const":"draft"},"truth_status":{"const":"inferred"},"entry_procedure_id":{"$ref":"#/$defs/identity_text"},"source_evidence":{"$ref":"#/$defs/evidence_list"},"procedure_nodes":{"type":"array","minItems":1,"maxItems":256,"uniqueItems":true,"items":{"$ref":"#/$defs/procedure_node"}},"procedure_edges":{"type":"array","minItems":0,"maxItems":512,"uniqueItems":true,"items":{"$ref":"#/$defs/procedure_edge"}}},"$defs":{"identity_text":{"type":"string","minLength":1,"maxLength":128,"pattern":"^[A-Za-z0-9_][A-Za-z0-9._:/@+=#-]*(?![\\s\\S])"},"annotation_text":{"type":"string","minLength":1,"maxLength":2048,"allOf":[{"pattern":"\\S"},{"pattern":"^[^\\u0000]*$"}]},"sha256_digest":{"type":"string","pattern":"^sha256:[0-9a-f]{64}(?![\\s\\S])"},"locale_annotations":{"type":"object","additionalProperties":false,"required":[],"properties":{"ko":{"$ref":"#/$defs/annotation_text"},"en":{"$ref":"#/$defs/annotation_text"},"ja":{"$ref":"#/$defs/annotation_text"},"zh":{"$ref":"#/$defs/annotation_text"},"vi":{"$ref":"#/$defs/annotation_text"},"es":{"$ref":"#/$defs/annotation_text"},"de":{"$ref":"#/$defs/annotation_text"},"fr":{"$ref":"#/$defs/annotation_text"}},"minProperties":1},"source_reference":{"allOf":[{"$ref":"https://schemas.contextualwisdomlab.org/conceptweave/semantic-candidate/0.1.0#/properties/evidence/items"},{"type":"object","properties":{"source_id":{"$ref":"#/$defs/identity_text"},"source_digest":{"$ref":"#/$defs/sha256_digest"},"location":{"$ref":"#/$defs/annotation_text"}}}]},"evidence_list":{"type":"array","minItems":1,"maxItems":64,"uniqueItems":true,"items":{"$ref":"#/$defs/source_reference"}},"artifact_reference":{"type":"object","additionalProperties":false,"required":["authority_ref","release_ref","artifact_digest","object_ref"],"properties":{"authority_ref":{"$ref":"#/$defs/identity_text"},"release_ref":{"$ref":"#/$defs/identity_text"},"artifact_digest":{"$ref":"#/$defs/sha256_digest"},"object_ref":{"$ref":"#/$defs/identity_text"}}},"procedure_node":{"type":"object","additionalProperties":false,"required":["procedure_id","procedure_kind","locale_labels","source_evidence"],"properties":{"procedure_id":{"$ref":"#/$defs/identity_text"},"procedure_kind":{"enum":["tool_operation","reasoning_step","skill_procedure","task_state"]},"locale_labels":{"$ref":"#/$defs/locale_annotations"},"source_evidence":{"$ref":"#/$defs/evidence_list"},"semantic_refs":{"type":"array","minItems":1,"maxItems":32,"uniqueItems":true,"items":{"$ref":"#/$defs/artifact_reference"}},"tool_contract_ref":{"$ref":"#/$defs/artifact_reference"}},"allOf":[{"if":{"properties":{"procedure_kind":{"const":"tool_operation"}},"required":["procedure_kind"]},"then":{"required":["tool_contract_ref"]}}]},"procedure_edge":{"type":"object","additionalProperties":false,"required":["source_procedure_id","relation_type","target_procedure_id","condition","guidance","pitfalls","source_evidence"],"properties":{"source_procedure_id":{"$ref":"#/$defs/identity_text"},"relation_type":{"enum":["leads_to","requires","enables"]},"target_procedure_id":{"$ref":"#/$defs/identity_text"},"condition":{"$ref":"#/$defs/locale_annotations"},"guidance":{"$ref":"#/$defs/locale_annotations"},"pitfalls":{"$ref":"#/$defs/locale_annotations"},"source_evidence":{"$ref":"#/$defs/evidence_list"}}}}} diff --git a/contracts/procedural-revision-proposal.schema.json b/contracts/procedural-revision-proposal.schema.json new file mode 100644 index 00000000..6aa09134 --- /dev/null +++ b/contracts/procedural-revision-proposal.schema.json @@ -0,0 +1 @@ +{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"urn:cwl:conceptweave:procedural-revision-proposal:v0.1.0-draft.1","title":"ConceptWeave offline procedural revision proposal","description":"Candidate generation envelope with training evidence and retained rejection references. It cannot carry validation answers, evaluator scores or self-issued approval fields. The declared partition is not proof of evidence provenance.","type":"object","additionalProperties":false,"required":["schema_version","proposal_id","proposal_origin","proposal_state","decision_authority","base_model_ref","candidate_model","evidence_partition","training_evidence","rejected_edit_refs","change_rationale"],"properties":{"schema_version":{"const":"0.1.0-draft.1"},"proposal_id":{"$ref":"urn:cwl:conceptweave:procedural-model-draft:v0.1.0-draft.1#/$defs/identity_text"},"proposal_origin":{"enum":["model_assisted","steward_authored"]},"proposal_state":{"const":"proposed"},"decision_authority":{"const":"none"},"base_model_ref":{"$ref":"urn:cwl:conceptweave:procedural-model-draft:v0.1.0-draft.1#/$defs/artifact_reference"},"candidate_model":{"$ref":"urn:cwl:conceptweave:procedural-model-draft:v0.1.0-draft.1"},"evidence_partition":{"const":"training"},"training_evidence":{"$ref":"urn:cwl:conceptweave:procedural-model-draft:v0.1.0-draft.1#/$defs/evidence_list"},"rejected_edit_refs":{"type":"array","minItems":0,"maxItems":64,"uniqueItems":true,"items":{"$ref":"urn:cwl:conceptweave:procedural-model-draft:v0.1.0-draft.1#/$defs/artifact_reference"}},"change_rationale":{"$ref":"urn:cwl:conceptweave:procedural-model-draft:v0.1.0-draft.1#/$defs/annotation_text"}}} diff --git a/docs/CONTEXT_MAP.md b/docs/CONTEXT_MAP.md index 5ea47792..893ad5cd 100644 --- a/docs/CONTEXT_MAP.md +++ b/docs/CONTEXT_MAP.md @@ -14,3 +14,15 @@ - context-graph-contracts <-> Interoperability: **Shared Kernel only for versioned public contracts**, kept minimal. - semantic-data-portal <- Interoperability: **Published Language**. SDP consumes releases; ConceptWeave does not read SDP application tables. - Keyverse -> future delivery layer: **Anti-Corruption Layer** for verified identity/tenant context. + +## Procedural model extension — Proposed, issue #42 + +- ConceptWeave Governance & Publication -> Noema: **Published Language + consumer ACL**. + ConceptWeave publishes procedural representations; Noema pins a compatible projection + per execution. Neither graph publication nor a relation label authorizes a tool call. +- Noema -> Source Observation: **Anti-Corruption Layer**, minimized observable training + evidence only; no hidden reasoning, secrets or foreign domain-truth replication. +- Independent evaluation -> Governance & Publication: **Customer/Supplier**, authenticated + exact-candidate paired evidence under a registered protocol; refiner output is not approval. +- The first local authoring schemas do not establish any of these live integrations. + Shared wire contracts remain owned by `context-graph-contracts`. diff --git a/docs/PRD.md b/docs/PRD.md index 0e68c400..444eac2f 100644 --- a/docs/PRD.md +++ b/docs/PRD.md @@ -79,3 +79,16 @@ Relational schema snapshot -> observed tables/columns/foreign keys -> concept/re - malformed/hostile source contracts rejected with bounded resource use; - semantic-model release can be reproduced from source receipts and approved proposal receipts; - buyer can inspect why each published artifact exists and which evidence supported it. + +## Procedural model engineering extension — Proposed, issue #42 + +Requirements PG-FR-1 through PG-FR-6 are defined in +[ADR-PG-20260910](adr/pg_20260910_procedural_model_engineering.md): evidence-bound +procedure authoring, concept/tool-contract alignment, independent offline evaluation, +steward publication, released consumer projection and inspectable authoring/review UX. +These identifiers are profile-scoped and do not renumber existing FRs or research work. + +The current slice delivers only draft/revision input schemas and structural fixtures. +It does not replace the initial relational vertical slice, deliver a graph editor, +run a model, or publish/activate procedural knowledge. A customer must ultimately +trace every suggested procedure to an approved model revision and exact source evidence. diff --git a/docs/TRD.md b/docs/TRD.md index ad5e1415..76b66bb3 100644 --- a/docs/TRD.md +++ b/docs/TRD.md @@ -56,3 +56,19 @@ Source artifacts are untrusted input. Adapters must enforce source size/type bou ## 10. Evaluation Evaluation must separate extraction recall, semantic correctness, structural correctness, ontology consistency, mapping accuracy, measure correctness, and governance outcomes. Model-judge scores may supplement but never replace deterministic golden fixtures and human-reviewed expert cases. + +## Procedural authoring contract slice — Proposed, issue #42 + +`contracts/procedural-model-draft.schema.json` and +`contracts/procedural-revision-proposal.schema.json` define separate local +`0.1.0-draft.1` inputs, reusing the existing evidence-reference grammar without +altering `semantic-candidate/0.1.0`. The Node script +`scripts/check_procedural_contracts.mjs` is test infrastructure using existing AJV +CLI 5.0.0; it is not production validation or a provider/runtime dependency. + +Draft validation is shape-only. Rust must separately enforce entry/edge/evidence +membership, unique identifiers, exact tenant/task/base identity, duplicate-key and +byte bounds, deterministic hashing and profile-specific topology. CGC release and +Noema projection tests must precede cross-product activation. The ADR records +transactional publication, independent evidence, multilingual labels and rollback +requirements; none is implied by a passing schema fixture. diff --git a/docs/adr/pg_20260910_procedural_model_engineering.md b/docs/adr/pg_20260910_procedural_model_engineering.md new file mode 100644 index 00000000..6f4bca35 --- /dev/null +++ b/docs/adr/pg_20260910_procedural_model_engineering.md @@ -0,0 +1,268 @@ +# ADR-PG-20260910: Govern procedural models in ConceptWeave; execute projections in Noema + +Status: Proposed. Date: 2026-09-10. Tracking: ConceptWeave #42; +ContextualWisdomLab/.github #2067. This namespaced decision identity avoids reusing +numeric ADR identities already occupied by concurrent Foundation/research work. + +## Problem and evidence + +The first CWL procedural-graph port put immutable graph/session values, bounded +neighborhood retrieval and preliminary candidate screening in Noema #585/#586. +Those runtime capabilities are useful and remain there. The adoption plan omitted +ConceptWeave's existing responsibility for evidence-bound semantic-model engineering, +leaving procedure authoring, concept alignment and governed publication without the +appropriate canonical owner. The user explicitly requested that correction. + +Lu et al. (2026) describe procedure/relation/procedure representation, localized +situational guidance that influences rather than dictates action, and offline edits +to topology and attributes using successful and failed trajectories. Edits are +screened against held-out performance; rejected edits are retained. The Korean +article motivated this request. These method statements do not prescribe CWL's +repository ownership, IAM, governance, locale or release design. This ADR introduces +those CWL choices and does not claim reproduction of the paper's benchmark results. + +Observed Foundation #1 at `60f14a6e85a83d56c2eea43b34d52b3366bb1735` +defines Source Observation, Semantic Discovery, Model Validation, Governance & +Publication and Interoperability. Its generic candidate schema does not represent +procedural nodes, localized edge annotations or revision proposals. Main observed +at `f4f440dd58c77d7cd90dff8a1eb2eeb9a9940425` contains README only. +These are dated source observations, not evergreen authority or released dependencies. + +## Alternatives and decision + +1. Keep authoring/refinement/publication entirely in Noema. This would make its + execution runtime compete with ConceptWeave's semantic engineering and review + lifecycle. Reject the ownership overlap, not the existing Noema source. +2. Move the entire runtime into ConceptWeave. This would duplicate Noema execution, + cancellation, checkpoint and tool boundaries. Reject. +3. Extend ConceptWeave's engineering contexts to procedural models and publish a + released projection for Noema. Select. Keep the domain facts and procedure + approval responsibility with each product/domain owner, and share only released + contracts. There is no new central runtime or product repository. + +| Responsibility | Canonical owner | +| --- | --- | +| Evidence intake, procedure candidate generation and alignment | ConceptWeave Source Observation / Semantic Discovery | +| Structural and semantic model validation | ConceptWeave Model Validation, Rust | +| Model revision, rejection history, steward review and publication | ConceptWeave Governance & Publication | +| Shared graph, evaluation and release interchange | context-graph-contracts; no wire-contract fork | +| Online projection, graph pinning, localization, guidance and lifecycle | Noema | +| Guide/refiner/solver model calls and provider routing | contextual-orchestrator | +| Task stimuli, item/rubric protocol and independent acceptance evidence | Evaluation owner / psychometrics-commons | +| Published-artifact catalog, discovery and consumer access experience | semantic-data-portal | +| Context map, architecture decisions and product adoption matrix | enterprise-architecture-core | +| Credential authority | keyverse | +| Business facts, purpose/IAM, policy and side-effect permission | Each product and its existing policy/security owners | + +Noema's preliminary arithmetic screening can remain a diagnostic implementation; +it is not the canonical store, evaluator authority or publisher. No forced source +migration, deletion, duplication or direct dependency on its mutable PR is added. + +## Ubiquitous language and semantic distinction + +A **procedure concept** identifies a described step, not an execution instance. +A **procedural model draft** is inferred candidate knowledge. A **revision proposal** +compares a retained base with a complete proposed model and training-evidence references. +A **validation receipt** reports checks under a named protocol; it is not an approval. +A **procedural model release** is an approved immutable representation. An **execution +projection** is a compatible consumer view pinned for a run; it cannot authorize tools. + +Keep three meanings distinct. Factual ontologies describe entities and relations; +procedural models describe possible steps and situational guidance; policy contracts +determine what a caller is permitted to do. An edge named `requires` is not automatically +an OWL restriction, an executable precondition, a transitive dependency rule or a grant. +`leads_to`, `requires` and `enables` are the initial advisory vocabulary only. A later +profile must specify any executable interpretation explicitly, outside this profile. + +Procedure-to-concept alignment retains qualified released object references. Similar +labels or embeddings do not justify merging identities. Product vocabulary and facts +stay with their domain owner; only references, not foreign payloads, enter this model. +Observed frequent behavior is not automatically a correct or normative procedure. + +## Product requirements and customer scenario + +PG-FR-1: A domain steward can inspect the SOP/API/manual or admitted observable +training evidence supporting each proposed procedure and relationship. + +PG-FR-2: Authoring preserves stable IDs, procedure categories, directed advisory +relations, localized condition/guidance/pitfalls and exact semantic/tool references. +Unresolved alignment remains visible rather than guessed or silently normalized. + +PG-FR-3: Offline revision comparison preserves the retained base and failed proposals. +The refiner receives approved training evidence, not validation answers or final-test +content. Independent evaluation compares the same task cases/model/tool/rubric context. + +PG-FR-4: Steward review and immutable publication bind exact candidate/artifact, +source evidence, validation and reviewer decisions. Publication is not execution +activation. Supersession, revocation and rollback preserve history. + +PG-FR-5: A Noema consumer admits only compatible released projections with explicit +unsupported/oversized/incomplete results. Existing executions retain their revision +and separately honor current cancellation, policy and revocation decisions. + +PG-FR-6: The authoring/review UI exposes source spans, graph differences, findings, +evaluation and reviewer receipts, and release history. DiagramWeave/inkspan and +product-owned reusable components should be integrated rather than cloned. + +Example: the central review profile describes reading a finding, reproducing it on +exact source, repairing it and verifying checks. ConceptWeave may propose a better +sequence after repeated failed reproductions. It cannot declare those findings true, +mark GitHub checks successful, approve a PR or merge it. A billing-domain procedure +likewise cannot change a rate or charge a customer merely because its model is published. + +## Implemented input-contract slice + +`contracts/procedural-model-draft.schema.json` has a new local draft identity; +`contracts/procedural-revision-proposal.schema.json` references it. Both use +`0.1.0-draft.1`. They do not change the existing generic candidate/0.1.0 schema, +Noema's graph schema or an already released shared contract. The evidence item +reuses the existing generic schema by `$ref`, with additional local digest/bound limits. + +The model envelope permits inferred/draft only. It contains tenant/task/domain-owner +references, an entry procedure ID, 1–256 procedure records, 0–512 relationship records, +and bounded evidence arrays. This profile's categories are `tool_operation`, +`reasoning_step`, `skill_procedure` and `task_state`; they are CWL profile choices. +Tool-operation candidates require an artifact-bound tool-contract reference, which +is still only an unverified reference at this layer. + +Locale maps admit `ko`, `en`, `ja`, `zh`, `vi`, `es`, `de`, `fr`, reject unsupported +keys, and require at least one nonblank bounded value. Partial authoring labels are +allowed; no eight-locale publication completeness is claimed. Ontology labels remain +separate from the database-backed UI translation ledger. Unicode normalization, +fallback and completeness rules require a later explicit release/profile contract. + +Revision proposals carry base artifact reference, complete candidate, declared training +evidence, retained rejection references and rationale. The envelope cannot carry +self-issued approval fields, holdout scores or raw trajectory fields. Free-form text +can still contain malicious or sensitive content; shape rejection is not scrubbing, +authentication, prompt-injection detection or proof of an actual training partition. + +The corpus has 46 cases: nine ordinary positive shapes, 33 invalid shapes, and four +shape-positive semantic-gap witnesses. In particular, a missing entry, a dangling +endpoint, and a duplicate identity with different record content need Rust checks; +`uniqueItems` only detects identical JSON records. The fourth witness requires +external evidence authenticity and exact base/scope comparison. They are deliberately +NOT described as valid graphs or approved revisions. + +`scripts/check_procedural_contracts.mjs` materializes the fixed unit corpus in a +private temporary directory, compiles the schemas, and validates the positive/negative +groups in-process with the repository-pinned `ajv` `8.20.0` Draft 2020-12 library. +Product installs that dependency from the committed lockfile with +`npm ci --ignore-scripts --no-audit --no-fund` before running the repository-owned +contract checks. Dynamic `npx`, `ajv-cli`, and child-process package execution are not +part of the current validation path. No coercion, default insertion or removal of +unknown fields is enabled. Product adds this fixture check and Node runner tests without +changing workflow triggers, permissions, concurrency, Rust/coverage/security gates or +the pinned dependencies. + +## Planned Rust and persistence boundary, not implemented here + +Construct a private immutable Rust procedural-model aggregate only after bounded +strict transport parsing and rejection of duplicate JSON keys. Validate node/edge/entry +membership, duplicate logical IDs/triples, evidence closure, exact tenant/task/base +binding, released semantic/tool references and nonempty necessary annotations. Define +cycle/reachability rules per task profile; do not force every procedural model into a DAG. + +Compute canonical material-content digests using a released CGC profile and conformance +fixtures, not a second incompatible copy of Noema's local hashing. Annotation, locale, +evidence or topology changes must affect the appropriate identity; input-order changes +must not. Separate candidate, structural, evidence, evaluation, approval and release IDs. + +State belongs to existing ConceptWeave contexts: `procedural_model_revision`, +`procedure_definition`, `procedure_relation`, `procedure_evidence_binding`, +`procedural_revision_proposal`, `procedural_rejection_record` and publication receipts +are planned 3NF entities, not implemented tables. Scope every key/FK by tenant/model. +Use immutable revision insertion, item-level UPSERT only where allowed, compare-and-swap +against the retained head, transactional outbox and idempotency receipts. Concurrent +publishers must not lose a revision or overwrite an accepted release. + +A release must bind provenance, source/profile versions, validity period, explicit +status, locale labels and evaluation/confidence status. Do not invent a numeric +confidence. It must be absent/unassessed or accompanied by an owner-defined calibrated +measurement and evidence. Authentication, stewardship and deployment activation remain +separate. No raw credential, hidden reasoning or unnecessary PII enters shared artifacts. + +```mermaid +sequenceDiagram + participant Source as Product evidence owner + participant CW as ConceptWeave + participant CO as contextual-orchestrator + participant EV as Independent evaluator + participant ST as Authorized steward + participant NO as Noema consumer + Source->>CW: Admitted immutable training evidence references + CW->>CO: Bounded candidate/refinement request + CO-->>CW: Untrusted procedural revision proposal + CW->>CW: Rust structural/semantic checks and base binding + CW->>EV: Exact candidate/base and registered evaluation protocol + EV-->>CW: Authenticated paired evaluation receipts + CW->>ST: Candidate, source, findings and evaluation evidence + ST-->>CW: Exact-candidate review decision + CW->>CW: CAS publication and immutable release receipt + CW-->>NO: Released compatible projection via contract/ACL + NO->>NO: Runtime admission, graph pinning and independent authorization +``` + +The sequence is intended architecture, not observed deployment. Rejected proposals +retain evaluation-context-scoped history without exposing holdout answer keys to the +refiner. Fresh final confirmation is required after repeated validation search; +mean non-regression is not statistical significance, validity or standard setting. + +## Rollout and acceptance + +Foundation/bootstrap remain prerequisites. First review this contract-only child. +Then implement Rust validation, independently verified evidence and publication, +released CGC interoperability, Noema projection and actual shadow invocation in that +order. No cross-repository runtime consumes this mutable branch. + +Shadow .github review and Naruon read-only tasks first. Compare no graph, fixed graph +and evolved graph under matched task/model/tool conditions, retaining failure +counts and denominators, correctness dimensions, tokens/cost and latency separately. +Each other product must identify an applicable agent task or a documented exclusion; +deterministic numerical kernels are not wrapped merely to claim adoption. + +Before canary, prove stale-evidence/tenant mismatch rejection, unsafe guidance cannot +widen tools, cancellation and live revocation, duplicate side-effect prevention, +publication conflicts and rollback after partial failures. Retain policy, quarantine, +egress and credential controls from their canonical owners. Existing timeouts or +provider termination rules are not replaced with a new blanket model time limit. + +No UI is built by this slice. Future UI needs Figma/token IDs, Storybook normal/loading/ +empty/error/permission/responsive/interaction states, keyboard/screenshot/E2E and +all supported locale layout checks before any UI delivery or accessibility claim. + +## Verification record and remaining uncertainty + +Predecessor authoring evidence at `300fed966643fa4bf2c4be29514b8796da764166` +remains historical: Python jsonschema 4.26.0 observed 46/46 structural expectations, +Node fixture-runner 16/16, and 14 ECMAScript pattern checks. The current supply-chain +repair at `61e08d597643a68515c126dbcca25c2495104adc` replaced dynamic AJV CLI execution +with locked in-process `ajv` `8.20.0`. The edited `.mjs` sources pass `node --check` +under Node 22.16.0, and the exact package manifest/lock pair reaches npm's offline +artifact lookup without a lock-consistency `EUSAGE` failure. This establishes source +syntax and manifest/lock consistency only. + +The current execution environment has neither a cached AJV package nor Rust 1.98, and +this Draft head has no Product workflow generation. Native exact-head AJV execution, +Rust workspace/fmt/strict Clippy/rustdoc/release, owned coverage, hosted security and +qualifying independent review therefore remain unproven. The four shape-positive +semantic witnesses remain expected RED for the planned Rust semantic validator; schema +shape is not semantic integrity, release approval, production performance or deployment. + +## References and traceability + +Lu, Y., Chen, Y., Wu, S., & Arık, S. Ö. (2026). *Procedural graphs: Self-evolving execution +structures for LLM agents* (arXiv:2609.09153v1). arXiv. +https://arxiv.org/abs/2609.09153 + +코난쌤. (2026, September 10). *Procedural Graph: LLM 에이전트를 위한 자가진화 절차 그래프 +(arXiv 2609.09153) 논문 정리*. +https://conanssam.com/posts/2026-09-10-procedural-graphs-self-evolving-llm-agents + +AJV contributors. (n.d.). *Ajv JSON schema validator*. +https://github.com/ajv-validator/ajv + +Method -> issue #42 -> PG-FR-1..6 -> these draft schemas -> +`contracts/fixtures/procedural-authoring.cases.json` -> existing Product fixture step. +The detailed source claims and CWL decisions above are intentionally distinguished; +no external benchmark score or paper claim substitutes for CWL evaluation evidence. diff --git a/docs/doctoring/procedural_model_evidence.md b/docs/doctoring/procedural_model_evidence.md new file mode 100644 index 00000000..ad2e70a1 --- /dev/null +++ b/docs/doctoring/procedural_model_evidence.md @@ -0,0 +1,32 @@ +# Procedural model source and conformance record + +Status: Proposed source evidence, not released product authority. Issue #42. +Decision, alternatives and APA references: +[ADR-PG-20260910](../adr/pg_20260910_procedural_model_engineering.md). + +The paper motivates procedural relationships, localized situational guidance and +offline graph refinement. ConceptWeave ownership, strict candidate-only envelopes, +eight-locale label grammar, independent approval and release/activation separation +are CWL adaptations, not claims made by that paper. No benchmark replication or +full supplementary implementation audit is claimed by this input-contract slice. + +| Trace | Exact local evidence scope | +| --- | --- | +| Procedural authoring grammar | Two new local draft schemas, referencing the unchanged generic evidence schema | +| Fixture generation | Same 46 materialized cases supplied to the independent validator and planned native AJV driver | +| Native test infrastructure | Node 22.16.0: 16 fixture-runner tests pass; this is not production Rust coverage | +| Independent schema validation | Python jsonschema 4.26.0: all three schemas pass meta-validation; 46/46 case expectations pass | +| Strict identity regression | Before the fix, 44/46 pass and two trailing-newline identity/digest cases incorrectly pass schema validation; after the fix, 46/46 pass | +| Native AJV availability | Offline probe returned ENOTCACHED; no native AJV or hosted Product GREEN is claimed | +| Semantic gaps | Four shape-positive witnesses explicitly require later entry/endpoint/identity/evidence checks | + +The strict-identity failure was caused by the conventional dollar anchor matching +before a final line terminator. The local identity and SHA-256 patterns now require +that no character remain after the matched value. The regression corpus retains +both counterexamples. This hardens input syntax; it does not authenticate a digest. + +Python was used only as an independent validation tool in the authoring environment; +no Python runtime or dependency was added to ConceptWeave. The repository driver uses +the existing AJV CLI 5.0.0 in Product, without coercion or changed security gates. +Rust model validation, authenticated source/partition/base binding, independent +evaluation, publication and consumer conformance remain separate prerequisites. diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index fdb83c64..1140e261 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -119,4 +119,29 @@ The live Local API replay remains acquisition/observation evidence only: 8,326 o No Foundation, #35, #9, #40, or downstream semantic publication is authorized by this snapshot. The closest prerequisite is central `.github#2051@70e8c1f...`: source repair is present, but exact-head required workflows and qualifying independent review are still pending. After its normal protected integration, #35 requires a fresh authenticated exact-head CodeQL run and independent approval; Foundation then requires its own exact-current Product and central evidence. Local predecessor evidence never transfers merely because a successor is docs-only. -No force push, destructive rebase, self-approval, review dismissal, fail-open scanner substitution, provider bypass, no-op trigger, synthetic status, live Zotero mutation, premature semantic publication, or release is acceptance evidence. \ No newline at end of file +No force push, destructive rebase, self-approval, review dismissal, fail-open scanner substitution, provider bypass, no-op trigger, synthetic status, live Zotero mutation, premature semantic publication, or release is acceptance evidence. + +## Procedural model engineering — 2026-09-10 scoped extension + +Tracking: issue #42 and ContextualWisdomLab/.github #2067; +[ADR-PG-20260910](adr/pg_20260910_procedural_model_engineering.md), Proposed. +The preceding Foundation snapshot is retained byte-for-byte as historical evidence; +this section updates only the procedural-model scope, not unrelated live PR counters. +Branch point observed: Foundation #1 `60f14a6e85a83d56c2eea43b34d52b3366bb1735`. +Protected-main observation remains bootstrap-only, not a semantic release. + +| Gap | This slice / next acceptance | +| --- | --- | +| Procedural authoring ownership missing from initial Noema-centric adoption | ConceptWeave authors, aligns, validates and publishes procedural models; Noema retains execution-local advice/lifecycle. Product facts and permissions remain with their owners. | +| No procedural draft/revision grammar | Two local `0.1.0-draft.1` schemas and 46 shape cases are added; the existing generic candidate schema and all Rust source remain unchanged. | +| Shape checks mistaken for model integrity | Four explicit shape-positive semantic-gap witnesses retain missing-entry, dangling-endpoint, duplicate-identity and evidence/scope authenticity gaps. Rust semantic admission is still required. | +| Offline refinement and independent evaluation | Training-only proposal envelope exists; actual source admission, CO generation, matched evaluation, final confirmation and persistent scoped rejections remain unimplemented by this slice. | +| Steward publication, release and consumer projection | Exact-candidate review, CAS publication, validity/confidence/provenance, signed immutable release, CGC interoperability and Noema projection remain required; no current mutable PR is a consumer dependency. | +| Product operation and authoring experience | Shadow comparison, product-specific authorization/idempotency, live revocation/rollback and eight-locale accessible editor/review UX still require actual implementation/evidence. | + +Local evidence is 46/46 Python-jsonschema input-shape cases from the Node materializer +and 16/16 Node fixture-runner tests. These are not native Product AJV/Rust/coverage or +hosted approval. AJV's offline availability check returned ENOTCACHED. The inherited +Product job remains subject to its existing Draft/prerequisite rules; no gate was +weakened or no-op rerun created. No model call, source mutation, semantic publication, +software release or product activation is delivered by this input-contract slice. diff --git a/docs/superpowers/plans/2026-09-10-procedural-model-engineering.md b/docs/superpowers/plans/2026-09-10-procedural-model-engineering.md new file mode 100644 index 00000000..7ebb9154 --- /dev/null +++ b/docs/superpowers/plans/2026-09-10-procedural-model-engineering.md @@ -0,0 +1,46 @@ +# Procedural model authoring implementation plan + +Goal: extend ConceptWeave's Semantic Model Engineering responsibility to procedural +knowledge without moving runtime execution or foreign domain truth into this product. +Architecture: ConceptWeave authors and validates model candidates; its Governance & +Publication context later publishes immutable artifacts. Noema consumes released +projections for execution-local advice. CO supplies model calls, not publication authority. +Tech stack: JSON Schema 2020-12 and the existing AJV CLI 5.0.0 test toolchain for this +first input-contract slice; production graph validation and application code remain Rust. +Spec: ../../adr/pg_20260910_procedural_model_engineering.md +Tracking: ConceptWeave #42 and ContextualWisdomLab/.github #2067. + +## First independently reviewable slice + +1. Define valid draft and revision examples, plus mutation cases before the schemas. +2. Confirm existing generic candidate input cannot express these procedural envelopes; + keep that original contract unchanged rather than reinterpreting its released identity. +3. Add `contracts/procedural-model-draft.schema.json`: procedure categories, advisory + relation vocabulary, localized annotations, qualified semantic references and source + evidence. Only inferred drafts are accepted; no tool/approval authority fields. +4. Add `contracts/procedural-revision-proposal.schema.json`: exact-base reference, + complete candidate, training-only evidence envelope, rejection references and rationale. + It cannot carry validation scores, final-test answers or a self-issued approval field. +5. Add a deterministic Node fixture-materialization/AJV driver using the already used + CLI version; wire it into the existing Product JSON-contract step, without new triggers. +6. Run schema meta-validation and every generated fixture; retain toolchain identities + and distinguish local validator evidence from native AJV and whole-workspace CI. +7. Link ADR, PRD/TRD/UML/security/test/recovery acceptance and product gaps. Publish a + Draft child of the current Foundation; preserve all existing stack deltas and gates. + +## Next slices, not delivered by input-schema validation + +- Rust graph construction: byte/duplicate-key bounds before parse, unique identities, + entry/endpoint membership, exact scope/parent matching, evidence closure, deterministic + content identity, immutable aggregate and profile-specific cycle/reachability checks. +- Ontology alignment: exact released concept/tool-contract references; relation direction + and unsupported profile detection. No silent synonym substitution or source-truth copy. +- CO-assisted discovery/refinement from admitted SOP/API/source/observable training evidence. +- Independently authenticated paired validation, final confirmation, scoped persistent + rejection history, steward decisions and CAS-controlled immutable publication. +- Released contract/projection to Noema, then catalog/EA projections and opt-in product + shadow/canary runs with policy, idempotency, cancellation, revocation and rollback evidence. + +Schema success is structural only. It does not prove endpoint membership, actual evidence +partition, signature validity, authorization, performance, publication or deployment. Do not +add a production endpoint, LLM caller, new Python runtime, or automatic activation here. diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..3410e092 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,71 @@ +{ + "name": "@contextualwisdomlab/conceptweave-ci", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@contextualwisdomlab/conceptweave-ci", + "version": "0.0.0", + "devDependencies": { + "ajv": "8.20.0" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-uri": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", + "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", + "dev": true, + "license": "BSD-3-Clause", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ] + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..843f255f --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "@contextualwisdomlab/conceptweave-ci", + "version": "0.0.0", + "private": true, + "scripts": { + "check:json-contracts": "node scripts/check_semantic_candidate_contracts.mjs && node --test scripts/tests/procedural_contract_fixtures.test.mjs && node scripts/check_procedural_contracts.mjs" + }, + "devDependencies": { + "ajv": "8.20.0" + } +} diff --git a/scripts/check_ci_contract.py b/scripts/check_ci_contract.py index f23b6c3f..e28abb94 100644 --- a/scripts/check_ci_contract.py +++ b/scripts/check_ci_contract.py @@ -1,4 +1,4 @@ -"""Fail closed when Product CI regresses on runner or coverage toolchain identity.""" +"""Fail closed when Product CI regresses on queue or quality-gate identity.""" from __future__ import annotations @@ -9,15 +9,14 @@ def main() -> int: - """Validate queue-admission, supersession, and branch-coverage invariants.""" + """Validate executable PR admission, supersession, and coverage invariants.""" workflow = WORKFLOW_PATH.read_text(encoding="utf-8") required_fragments = ( "runs-on: ubuntu-24.04", - "types: [opened, synchronize, reopened, ready_for_review, converted_to_draft, closed]", + "types: [opened, synchronize, reopened, ready_for_review]", "group: ${{ github.workflow }}-${{ github.repository }}-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.run_id }}", "cancel-in-progress: ${{ github.event_name == 'pull_request' }}", - "if: ${{ github.event_name != 'pull_request' || (github.event.action != 'closed' && github.event.pull_request.draft == false) }}", "actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0", "COVERAGE_TOOLCHAIN: nightly-2026-08-20", 'rustup toolchain install "$COVERAGE_TOOLCHAIN" --profile minimal --component llvm-tools-preview', @@ -28,6 +27,19 @@ def main() -> int: "Product CI contract missing required fragment(s): " + ", ".join(missing) ) + prohibited_fragments = ( + "converted_to_draft", + "types: [opened, synchronize, reopened, ready_for_review, converted_to_draft, closed]", + "github.event.pull_request.draft == false", + "github.event.action != 'closed'", + ) + present = [fragment for fragment in prohibited_fragments if fragment in workflow] + if present: + raise SystemExit( + "Product CI contract contains dead or Draft-suppressing fragment(s): " + + ", ".join(present) + ) + if "runs-on: ubuntu-latest" in workflow: raise SystemExit( "Product CI must not use ubuntu-latest while current organization " diff --git a/scripts/check_procedural_contracts.mjs b/scripts/check_procedural_contracts.mjs new file mode 100644 index 00000000..9163c5bb --- /dev/null +++ b/scripts/check_procedural_contracts.mjs @@ -0,0 +1,104 @@ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import Ajv2020 from "ajv/dist/2020.js"; + +const forbiddenKeys = new Set(["__proto__", "prototype", "constructor"]); +const schemaFiles = { + model: "procedural-model-draft.schema.json", + revision: "procedural-revision-proposal.schema.json", +}; +const requireFixture = predicate => { + if (!predicate) throw new Error("invalid_fixture_protocol"); +}; + +/** Test-only corpus expansion; it never authorizes graph changes or handles product requests. */ +export function materializeContractCases(caseManifest, fixtureBases) { + requireFixture(caseManifest?.validation_scope === "input_shape_only"); + requireFixture(caseManifest.fixture_data_policy === "synthetic_unit_test_only"); + requireFixture(Array.isArray(caseManifest.case_rows) && caseManifest.case_rows.length > 0 && caseManifest.case_rows.length <= 256); + const caseNames = new Set(); + return caseManifest.case_rows.map(caseRow => { + requireFixture(typeof caseRow.case_name === "string" && /^[a-z][a-z0-9_]{1,95}$/.test(caseRow.case_name)); + requireFixture(!caseNames.has(caseRow.case_name)); + caseNames.add(caseRow.case_name); + requireFixture(Object.hasOwn(schemaFiles, caseRow.base_name) && Object.hasOwn(fixtureBases, caseRow.base_name)); + requireFixture(typeof caseRow.shape_valid === "boolean"); + requireFixture(typeof caseRow.semantic_expectation === "string" && caseRow.semantic_expectation.length > 0); + requireFixture(Array.isArray(caseRow.changes) && caseRow.changes.length <= 16); + const payload = structuredClone(fixtureBases[caseRow.base_name]); + for (const changeRecord of caseRow.changes) { + requireFixture(changeRecord.operation === "set" || changeRecord.operation === "remove"); + requireFixture(Array.isArray(changeRecord.field_path) && changeRecord.field_path.length > 0 && changeRecord.field_path.length <= 16); + for (const fieldKey of changeRecord.field_path) { + requireFixture((typeof fieldKey === "string" && fieldKey.length > 0 && !forbiddenKeys.has(fieldKey)) || (Number.isSafeInteger(fieldKey) && fieldKey >= 0)); + } + let fieldParent = payload; + for (const fieldKey of changeRecord.field_path.slice(0, -1)) { + requireFixture(fieldParent !== null && typeof fieldParent === "object" && Object.hasOwn(fieldParent, fieldKey)); + fieldParent = fieldParent[fieldKey]; + } + requireFixture(fieldParent !== null && typeof fieldParent === "object"); + const finalKey = changeRecord.field_path.at(-1); + if (changeRecord.operation === "remove") { + requireFixture(Object.hasOwn(fieldParent, finalKey)); + delete fieldParent[finalKey]; + } else { + requireFixture(Object.hasOwn(changeRecord, "field_value")); + Object.defineProperty(fieldParent, finalKey, { + value: structuredClone(changeRecord.field_value), enumerable: true, writable: true, configurable: true, + }); + } + } + return {...caseRow, payload}; + }); +} + +/** Builds in-process Draft 2020-12 validators from repository-owned schemas. */ +export function createProceduralValidators(repositoryRoot) { + const readJson = path => JSON.parse(readFileSync(resolve(repositoryRoot, path), "utf8")); + const semanticCandidateSchema = readJson("contracts/semantic-candidate.schema.json"); + const proceduralModelSchema = readJson("contracts/procedural-model-draft.schema.json"); + const proceduralRevisionSchema = readJson("contracts/procedural-revision-proposal.schema.json"); + const ajv = new Ajv2020({allErrors: true, strict: true}); + ajv.addSchema(semanticCandidateSchema); + ajv.addSchema(proceduralModelSchema); + ajv.addSchema(proceduralRevisionSchema); + const validators = { + model: ajv.getSchema(proceduralModelSchema.$id), + revision: ajv.getSchema(proceduralRevisionSchema.$id), + }; + requireFixture(typeof validators.model === "function" && typeof validators.revision === "function"); + return validators; +} + +/** Evaluates every materialized shape case without coercion, defaults, or external command execution. */ +export function validateContractCases(validators, outputCases) { + for (const caseRow of outputCases) { + const validator = validators[caseRow.base_name]; + requireFixture(typeof validator === "function"); + const actualValid = validator(caseRow.payload); + if (actualValid !== caseRow.shape_valid) { + const details = validator.errors ? JSON.stringify(validator.errors) : "[]"; + throw new Error(`procedural_contract_validation_failed:${caseRow.case_name}:${details}`); + } + } + return { + validation_scope: "input_shape_only", + checked_cases: outputCases.length, + semantic_gap_witnesses: outputCases.filter(item => item.semantic_expectation !== "not_evaluated").length, + publication_authorized: false, + activation_authorized: false, + }; +} + +function runFixtureChecks() { + const repositoryRoot = fileURLToPath(new URL("../", import.meta.url)); + const readFixture = filename => JSON.parse(readFileSync(resolve(repositoryRoot, "contracts/fixtures", filename), "utf8")); + const fixtureBases = {model: readFixture("procedural-model.base.json"), revision: readFixture("procedural-revision.base.json")}; + const outputCases = materializeContractCases(readFixture("procedural-authoring.cases.json"), fixtureBases); + const validators = createProceduralValidators(repositoryRoot); + console.log(JSON.stringify(validateContractCases(validators, outputCases))); +} + +if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) runFixtureChecks(); diff --git a/scripts/check_semantic_candidate_contracts.mjs b/scripts/check_semantic_candidate_contracts.mjs new file mode 100644 index 00000000..60ee784d --- /dev/null +++ b/scripts/check_semantic_candidate_contracts.mjs @@ -0,0 +1,26 @@ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import Ajv2020 from "ajv/dist/2020.js"; + +const repositoryRoot = fileURLToPath(new URL("../", import.meta.url)); +const readJson = path => JSON.parse(readFileSync(resolve(repositoryRoot, path), "utf8")); +const schema = readJson("contracts/semantic-candidate.schema.json"); +const validator = new Ajv2020({allErrors: true, strict: true}).compile(schema); + +const cases = [ + ["contracts/fixtures/semantic-candidate.valid.json", true], + ["contracts/fixtures/semantic-candidate.invalid-whitespace.json", false], + ["contracts/fixtures/semantic-candidate.invalid-published-truth.json", false], + ["contracts/fixtures/semantic-candidate.invalid-state-truth-mismatch.json", false], +]; + +for (const [fixturePath, expectedValid] of cases) { + const actualValid = validator(readJson(fixturePath)); + if (actualValid !== expectedValid) { + const details = validator.errors ? JSON.stringify(validator.errors) : "[]"; + throw new Error(`semantic_candidate_contract_validation_failed:${fixturePath}:${details}`); + } +} + +console.log(JSON.stringify({checked_cases: cases.length, schema_id: schema.$id})); diff --git a/scripts/tests/procedural_contract_fixtures.test.mjs b/scripts/tests/procedural_contract_fixtures.test.mjs new file mode 100644 index 00000000..2f8b8285 --- /dev/null +++ b/scripts/tests/procedural_contract_fixtures.test.mjs @@ -0,0 +1,76 @@ +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { test } from "node:test"; +import { + materializeContractCases, + createProceduralValidators, + validateContractCases, +} from "../check_procedural_contracts.mjs"; + +const repositoryRoot = fileURLToPath(new URL("../../", import.meta.url)); +const readFixture = name => JSON.parse(readFileSync(resolve(repositoryRoot, "contracts/fixtures", name), "utf8")); +const fixtureBases = {model: readFixture("procedural-model.base.json"), revision: readFixture("procedural-revision.base.json")}; +const caseManifest = readFixture("procedural-authoring.cases.json"); + +// These tests cover the fixture protocol and real in-process JSON Schema validation only. +test("materializes every registered case without changing retained fixture bytes", () => { + const beforeBytes = JSON.stringify({fixtureBases, caseManifest}); + const outputCases = materializeContractCases(caseManifest, fixtureBases); + assert.equal(outputCases.length, 46); + assert.equal(outputCases.filter(item => !item.shape_valid).length, 33); + assert.equal(outputCases.filter(item => item.semantic_expectation !== "not_evaluated").length, 4); + assert.equal(JSON.stringify({fixtureBases, caseManifest}), beforeBytes); + outputCases[0].payload.procedure_nodes[0].locale_labels.en = "Modified test instance"; + assert.equal(fixtureBases.model.procedure_nodes[0].locale_labels.en, "Read review evidence"); +}); + +test("keeps semantic gap witnesses distinct from ordinary shape-positive inputs", () => { + const outputCases = materializeContractCases(caseManifest, fixtureBases); + const gapCase = outputCases.find(item => item.case_name === "known_gap_dangling_endpoint"); + assert.equal(gapCase.shape_valid, true); + assert.equal(gapCase.semantic_expectation, "must_reject_dangling_endpoint"); + assert.notEqual(gapCase.payload.procedure_edges[0].target_procedure_id, fixtureBases.model.procedure_edges[0].target_procedure_id); +}); + +for (const [caseName, mutation] of [ + ["wrong scope", value => {value.validation_scope = "runtime_approval";}], + ["empty corpus", value => {value.case_rows = [];}], + ["unknown base", value => {value.case_rows[0].base_name = "../secret";}], + ["duplicate name", value => {value.case_rows[1].case_name = value.case_rows[0].case_name;}], + ["unsafe filename", value => {value.case_rows[0].case_name = "../outside";}], + ["nonboolean expectation", value => {value.case_rows[0].shape_valid = "true";}], + ["missing gap disposition", value => {delete value.case_rows[0].semantic_expectation;}], + ["unknown operation", value => {value.case_rows[0].changes = [{operation: "execute", field_path: ["model_id"]}];}], + ["empty field path", value => {value.case_rows[0].changes = [{operation: "remove", field_path: []}];}], + ["prototype traversal", value => {value.case_rows[0].changes = [{operation: "set", field_path: ["__proto__", "polluted"], field_value: true}];}], + ["absent intermediate", value => {value.case_rows[0].changes = [{operation: "set", field_path: ["absent", "child"], field_value: true}];}], + ["absent removal", value => {value.case_rows[0].changes = [{operation: "remove", field_path: ["absent"]}];}], + ["missing replacement", value => {value.case_rows[0].changes = [{operation: "set", field_path: ["model_id"]}];}], +]) test(`rejects invalid fixture protocol: ${caseName}`, () => { + const changedManifest = structuredClone(caseManifest); + mutation(changedManifest); + assert.throws(() => materializeContractCases(changedManifest, fixtureBases), /invalid_fixture_protocol/); +}); + +test("validates all shape cases in process through the locked AJV library", () => { + const outputCases = materializeContractCases(caseManifest, fixtureBases); + const summary = validateContractCases(createProceduralValidators(repositoryRoot), outputCases); + assert.equal(summary.checked_cases, 46); + assert.equal(summary.semantic_gap_witnesses, 4); + assert.equal(summary.publication_authorized, false); + assert.equal(summary.activation_authorized, false); +}); + +test("keeps JSON Schema validation off dynamic package execution paths", () => { + const packageManifest = JSON.parse(readFileSync(resolve(repositoryRoot, "package.json"), "utf8")); + const packageLock = JSON.parse(readFileSync(resolve(repositoryRoot, "package-lock.json"), "utf8")); + const workflow = readFileSync(resolve(repositoryRoot, ".github/workflows/product.yml"), "utf8"); + const checker = readFileSync(resolve(repositoryRoot, "scripts/check_procedural_contracts.mjs"), "utf8"); + assert.equal(packageManifest.devDependencies.ajv, "8.20.0"); + assert.equal(packageLock.packages["node_modules/ajv"].version, "8.20.0"); + assert.match(workflow, /npm ci --ignore-scripts --no-audit --no-fund/); + assert.doesNotMatch(workflow, /\bnpx\b|ajv-cli/); + assert.doesNotMatch(checker, /spawnSync|\bnpx\b|ajv-cli/); +});