Skip to content

v18 Continuum opening campaign#91

Open
flyingrobots wants to merge 8 commits into
mainfrom
v18-continuum-opening
Open

v18 Continuum opening campaign#91
flyingrobots wants to merge 8 commits into
mainfrom
v18-continuum-opening

Conversation

@flyingrobots
Copy link
Copy Markdown
Member

@flyingrobots flyingrobots commented May 21, 2026

Summary

  • Harden Continuum artifact ingestion around real Continuum fixture JSON and Wesley realization manifest JSON.
  • Require explicit load context for artifact authority, rejecting self-attested authority fields and local/handwritten mirror authority.
  • Update BEARING and cycle docs for the non-prefixed branch and completed task 5 evidence.

Supersedes #90; this PR replaces the prefixed branch with v18-continuum-opening.

Validation

  • npm run lint
  • npm run typecheck:src
  • npm run typecheck:test
  • npm run typecheck:surface
  • npm run typecheck:policy
  • npm run lint:sludge
  • npm run lint:quarantine-graduate
  • npx --yes markdownlint-cli docs/BEARING.md docs/design/0146-v18-continuum-compatibility-charter/v18-continuum-compatibility-charter.md docs/design/0149-v18-continuum-artifact-ingestion/v18-continuum-artifact-ingestion.md
  • npx vitest run test/unit/domain/continuum/ContinuumArtifactIngestionPolicy.test.ts test/unit/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.test.ts test/unit/domain/index.exports.test.ts test/unit/domain/errors/index.test.ts
  • npm run test:local (447 files, 6821 tests)
  • npm run test:coverage:ci (92.14% lines; threshold 91.90%)
  • Pre-push IRONCLAD M9 gates passed

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Continuum artifact compatibility support with artifact descriptors, ingestion policies, and family identifiers
    • Introduced JSON file adapter for loading and validating Continuum artifacts
  • Documentation

    • Completed v17 release documentation
    • Added v18 design charters defining Continuum compatibility requirements
    • Updated product vision to clarify compatibility posture
    • Revised backlog documentation with updated terminology
  • Tests

    • Added comprehensive test coverage for Continuum artifact validation and ingestion

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

📝 Walkthrough

Walkthrough

This PR implements v18 Continuum artifact ingestion capability: design docs establish the v18 graph-model convergence strategy, domain models enforce artifact authority and descriptor validation, a JSON adapter parses Wesley manifests and Continuum fixtures safely, and public API exports complete the integration for artifact handling across the ecosystem.

Changes

V18 Continuum Artifact Ingestion

Layer / File(s) Summary
V18 Continuum Strategy Documentation
docs/BEARING.md, docs/VISION.md, docs/design/0124-*.md, docs/design/0145-*/push-pr-review-merge.md, docs/design/0146-0149/, docs/design/continuum-categories.tex, docs/method/backlog/*, docs/method/retro/*
Design charters and method docs establish v18 as Continuum-compatible graph-model convergence, replacing substrate framing. Includes v17 release closure, v18 contract matrix, optic realization map, and artifact ingestion task definitions.
Domain Models & Artifact Validation
src/domain/continuum/ContinuumFamilyId.ts, src/domain/continuum/ContinuumArtifactAuthority.ts, src/domain/continuum/ContinuumArtifactDescriptor.ts, src/domain/continuum/ContinuumArtifactIngestionPolicy.ts, src/domain/errors/ContinuumArtifactAuthorityError.ts, src/domain/errors/index.ts, test/unit/domain/continuum/*, test/unit/domain/errors/*, test/unit/domain/index.exports.test.ts
Core types validate artifact family IDs, authority postures (generated/local/handwritten/self-attested), and descriptor fields with normalization. ContinuumArtifactIngestionPolicy gates acceptance of generated artifacts. Tests confirm validation rules, type safety, and constructor behavior.
JSON File Adapter & Parsing
src/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.ts, test/fixtures/continuum/receipt-family-*.json, test/unit/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.test.ts
Adapter safely parses Wesley realization manifests and Continuum family fixtures from disk/memory JSON, validates schemas and required fields (integrity sealing, leg inventory), rejects unknown keys, and converts to descriptor fields. Comprehensive tests cover acceptance of valid manifests and fixtures, rejection of unsealed/malformed/unauthorized inputs.
Public API Exports & Integration
index.ts
Entry point exports artifact domain classes, custom error, ingestion policy, and adapter, plus corresponding type exports for authority values, descriptor fields, family IDs, and JSON load context.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • git-stunts/git-warp#41: Updates d.ts "declaration surface" parser to correctly handle export type / export declare syntax, directly affecting validation of the new Continuum artifact type exports added in this PR's index.ts.

Poem

🐰 Hopping through schemas with authority-tested grace,
Wesley and Continuum fixtures find their place,
Domain models frozen, validators tight,
V18's artifact ingestion shines so bright!
Adapters parse JSON, ingestion gates pass,
A Continuum-compatible graph lands at last. 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description provides a clear summary of changes, documents the validation steps performed, and includes ADR checks template. However, all ADR check boxes are unchecked with no explanation of whether they apply. Complete the ADR checks section by either checking the boxes if conditions are satisfied or explicitly documenting why they are not applicable to this PR.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main objective: the v18 Continuum opening campaign, which aligns with the primary focus of implementing Continuum artifact ingestion hardening and updating related documentation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v18-continuum-opening

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 and usage tips.

@github-actions
Copy link
Copy Markdown

Release Preflight

  • package version: 17.0.0
  • prerelease: false
  • npm dist-tag on release: latest
  • npm pack dry-run: passed
  • jsr publish dry-run: passed

If you tag this commit as v17.0.0, release workflow will publish.

@flyingrobots
Copy link
Copy Markdown
Member Author

@codex Self-review pass after clean-worktree check and git fetch origin.

Issue count: Critical 0, Major 3, Minor 2.

Severity File / lines Infraction Evidence Recommended mitigation prompt
Major src/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.ts:166-177, src/domain/continuum/ContinuumArtifactIngestionPolicy.ts:13-15 Shape and authority are not bound together. The adapter always copies context.authority into the descriptor, and the policy accepts either generated-artifact or generated-fixture for every descriptor. A Wesley realization manifest can therefore be admitted as a generated fixture, and a Continuum fixture can be admitted as a generated artifact. That weakens the branch goal of making generated-family authority explicit and non-folkloric. Update ContinuumArtifactJsonFileAdapter so parsed artifact shape determines the allowed authority: Wesley realization manifests must require generated-artifact, Continuum family fixtures must require generated-fixture, and mismatched context authority must throw AdapterValidationError. Add regression tests for both mismatches.
Major src/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.ts:127-135, src/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.ts:158-162 Caller context can override parsed artifact kind. context.artifactKind can replace the canonical parsed kind for both Wesley manifests and Continuum fixtures. This lets an adapter caller emit a descriptor whose artifactKind contradicts the JSON shape the adapter just parsed. Remove artifactKind from ContinuumArtifactJsonLoadContext, or require it to exactly match the parsed shape before descriptor construction. Add tests proving a Wesley manifest cannot be labeled continuum.family.fixture and a Continuum fixture cannot be labeled wesley.realization.manifest.v1.
Major src/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.ts:257-281, src/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.ts:284-302 Wesley generated inventory can be empty or internally inconsistent. readGeneratedLegs accepts {} because it freezes whatever keys exist and never requires at least one leg. readOptionalNumber(leg, artifactCount) validates only numeric shape; it does not require artifactCount === files.length, so a sealed manifest can claim generated artifacts without a matching file inventory. Harden Wesley generatedLegs parsing: require at least one generated leg, require artifactCount to equal the number of file entries when present, and reject positive artifactCount with missing or empty files. Add tests for empty generatedLegs, count mismatch, and positive count without files.
Minor test/fixtures/continuum/receipt-family-wesley-realization-manifest.json:4 Fixture commits a machine-specific absolute path. The fixture stores /Users/james/git/continuum/... in canonicalSchemaPath. This is not used by the adapter, but it bakes a local workstation path into a shared repo fixture and makes the test data look less portable than the parser actually requires. Replace the absolute canonicalSchemaPath fixture value with a repo-neutral path or remove the optional field from the fixture if this test does not exercise it. Keep one parser test that validates canonicalSchemaPath as an optional string without committing a user-local path.
Minor docs/design/0149-v18-continuum-artifact-ingestion/v18-continuum-artifact-ingestion.md:104-116 Verification prose records a command known to exit nonzero as an observed coverage result. The doc lists npx vitest run --coverage ... and then states that the command exits nonzero because global thresholds apply to the subset. That is accurate but easy to misread as a passing verification command in a completed cycle doc. Move the targeted coverage command under a clearly labeled diagnostic coverage note section, or replace it with a command/configuration that exits zero while reporting only touched-file coverage. Keep the full passing coverage CI command as the authoritative verification line.

@flyingrobots
Copy link
Copy Markdown
Member Author

@coderabbitai review please

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

🧩 Analysis chain

I'll gather the relevant files before starting the full review.


🏁 Script executed:

#!/bin/bash
echo "=== ContinuumArtifactJsonFileAdapter.ts ==="
cat src/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.ts

echo ""
echo "=== ContinuumArtifactIngestionPolicy.ts ==="
cat src/domain/continuum/ContinuumArtifactIngestionPolicy.ts

echo ""
echo "=== Wesley realization manifest fixture ==="
cat test/fixtures/continuum/receipt-family-wesley-realization-manifest.json

echo ""
echo "=== Ingestion design doc (lines 90-130) ==="
sed -n '90,130p' docs/design/0149-v18-continuum-artifact-ingestion/v18-continuum-artifact-ingestion.md

echo ""
echo "=== ContinuumArtifactIngestionPolicy test ==="
cat test/unit/domain/continuum/ContinuumArtifactIngestionPolicy.test.ts

echo ""
echo "=== ContinuumArtifactJsonFileAdapter test ==="
cat test/unit/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.test.ts

echo ""
echo "=== Domain errors index ==="
fd -e ts -e js "index" src/domain/errors/ | head -5
cat src/domain/errors/index.ts 2>/dev/null || fd "index" src/domain/errors | head -3 | xargs cat

echo ""
echo "=== AdapterValidationError ==="
rg -rn "AdapterValidationError" --type ts -C3 | head -60

echo ""
echo "=== ContinuumArtifactJsonLoadContext type ==="
rg -rn "ContinuumArtifactJsonLoadContext" --type ts -C5 | head -80

Length of output: 57081


🏁 Script executed:

#!/bin/bash
echo "=== AdapterValidationError source ==="
fd "AdapterValidationError" src/ | head -5 | xargs cat

echo ""
echo "=== hasGeneratedAuthority definition ==="
rg -n "hasGeneratedAuthority" --type ts -C5

echo ""
echo "=== ContinuumArtifactAuthority allowed values ==="
cat src/domain/continuum/ContinuumArtifactAuthority.ts 2>/dev/null || fd "ContinuumArtifactAuthority.ts" src | xargs cat

echo ""
echo "=== domain/index.exports test ==="
cat test/unit/domain/index.exports.test.ts | grep -i "adapter\|validation" | head -20

echo ""
echo "=== domain errors index.test.ts ==="
cat test/unit/domain/errors/index.test.ts | head -40

Length of output: 7949


@flyingrobots — full review complete. I read all five flagged locations and the supporting types. Findings below.


Review: v18 Continuum Opening Campaign

✅ All five self-review items confirmed


🔴 Major 1 — Shape and authority are not bound together

Confirmed. ContinuumArtifactAuthority.isGeneratedAuthority() returns true for both generated-artifact and generated-fixture:

// ContinuumArtifactAuthority.ts
isGeneratedAuthority(): boolean {
  return (
    this.value === GENERATED_ARTIFACT_AUTHORITY ||  // 'generated-artifact'
    this.value === GENERATED_FIXTURE_AUTHORITY       // 'generated-fixture'
  );
}

ContinuumArtifactIngestionPolicy.assertGeneratedAuthority() calls only descriptor.hasGeneratedAuthority() — it never inspects artifactKind. And descriptorFields() in the adapter copies context.authority unconditionally regardless of which parsing branch executed. Together, these mean:

  • A Wesley manifest loaded with authority: 'generated-fixture'admitted
  • A Continuum family fixture loaded with authority: 'generated-artifact'admitted

The intended invariant — that Wesley manifests carry generated-artifact and fixtures carry generated-fixture — is not enforced anywhere in the current code.


🔴 Major 2 — Caller context can override parsed artifact kind

Confirmed. Both parsing branches delegate artifactKind to the caller:

// wesleyManifestFields()  [~line 131]
artifactKind: context.artifactKind ?? WESLEY_REALIZATION_MANIFEST_KIND,

// parseContinuumFamilyFixture()  [~line 161]
artifactKind: context.artifactKind ?? CONTINUUM_FIXTURE_KIND,

The parsed shape determines which branch runs, but the emitted descriptor's artifactKind can be entirely different from the shape that was parsed. A caller can pass artifactKind: 'continuum.family.fixture' against a Wesley manifest — or vice versa — and the descriptor will silently misrepresent the underlying JSON shape.


🔴 Major 3 — Wesley generated inventory can be empty or internally inconsistent

Confirmed, with a nuance. readGeneratedLegs does not require at least one leg:

// readGeneratedLegs()  [~line 258]
const names = Object.freeze(Object.keys(generatedLegs).sort());  // {} → []
// No minimum-leg check follows

Several existing test fixtures that use "generatedLegs": {} throw AdapterValidationError — but for other reasons (status: "open", malformed targets). A sealed, otherwise-valid manifest with "generatedLegs": {} would currently pass silently.

The artifactCount-vs-files.length cross-check is also absent. Worth noting: the test "accepts Wesley generated legs before the compiler writes file inventory" deliberately allows artifactCount: 0 with no files, which appears to be an intentional design allowance for pre-population manifests. The unguarded cases that remain are:

  • generatedLegs: {} (zero legs entirely)
  • artifactCount > 0 with files absent or with files.length !== artifactCount

🟡 Minor 4 — Machine-specific absolute path in fixture

Confirmed. test/fixtures/continuum/receipt-family-wesley-realization-manifest.json line 4:

"canonicalSchemaPath": "/Users/james/git/continuum/schemas/continuum-receipt-family.graphql"

The field is optional in the adapter (readOptionalString) and is not asserted in any test, so it's purely cosmetic debt — but it does bake a local workstation path into a shared repo fixture.


🟡 Minor 5 — Verification prose documents a known-nonzero exit command

Confirmed. The design doc at lines 109–115 states the targeted npx vitest run --coverage command exits nonzero because the global threshold is applied to the two-suite subset. This is accurate and explained, but a reader skimming the verification record could misread it as a passing CI command. Moving it under a clearly-labeled diagnostic note (separate from the authoritative npm run test:coverage:ci line) would remove the ambiguity.


Additional observation — AdapterValidationError intentionally excluded from domain barrel

AdapterValidationError is imported directly from its file by both the adapter and the tests — it is not in src/domain/errors/index.ts, and this appears to be intentional: test/unit/domain/errors/index.test.ts explicitly locks the exact 18-error export surface and excludes it. No action needed; the boundary is deliberate.


Summary

# Severity Status
1 Major Confirmed — generated-artifact / generated-fixture are both admitted for any shape; policy has no shape-authority coupling
2 Major Confirmed — context.artifactKind can produce a descriptor whose artifactKind contradicts the parsed JSON shape
3 Major Confirmed — empty generatedLegs: {} passes silently; positive artifactCount is never cross-checked against actual files.length
4 Minor Confirmed — absolute workstation path in shared fixture
5 Minor Confirmed — nonzero-exit command in verification prose
✅ Actions performed

Review triggered.

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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/domain/continuum/ContinuumArtifactIngestionPolicy.ts`:
- Around line 13-19: assertGeneratedAuthority currently only checks
descriptor.hasGeneratedAuthority() and therefore allows mismatched
kind/authority pairs; update it to validate that the descriptor's actual
authority exactly matches the expected generated authority for its shape/kind.
In practice, inside assertGeneratedAuthority use ContinuumArtifactDescriptor's
identifying property (e.g., kind or shape) to determine the expected generated
authority (compute or call a helper like
expectedGeneratedAuthorityForKind(kind)) and then check both
descriptor.hasGeneratedAuthority() and
descriptor.authority.equals(expectedAuthority); if either fails throw the
existing ContinuumArtifactAuthorityError with a message that includes
descriptor.familyId, descriptor.kind (or shape) and the actual vs expected
authority so mismatches like Wesley manifest + generated-fixture or fixture +
generated-artifact are rejected. Ensure you reference and update
assertGeneratedAuthority, ContinuumArtifactDescriptor, and the thrown
ContinuumArtifactAuthorityError only.

In `@src/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.ts`:
- Around line 133-135: The parsed JSON must determine artifactKind and authority
rather than letting context override them: in ContinuumArtifactJsonFileAdapter's
JSON parsing logic (the block that sets generatedBy, artifactKind, targets using
readStringArray/readString), read the artifactKind and authority from the source
JSON shape and bind artifactKind to that value (do not default to
context.artifactKind), and validate that context.authority (if provided) matches
the parsed authority; if they mismatch, throw a validation/error. Apply the same
enforcement where similar parsing occurs (the other parsing blocks around the
indicated ranges 158-163 and 166-177).
- Around line 258-303: readGeneratedLegs currently accepts empty generatedLegs
and doesn't validate artifactCount against the actual files, allowing
inconsistent sealed manifests; update readGeneratedLegs (and readGeneratedFiles
usage) so that after calling readOptionalNumber(leg, 'artifactCount') and
collecting files via readGeneratedFiles(leg, name) you validate: if
artifactCount is present and not equal to files.length throw an
AdapterValidationError with a clear message referencing the leg name, and
additionally reject an entirely empty generatedLegs map by throwing an
AdapterValidationError when names.length === 0; use the existing
AdapterValidationError type and the functions readOptionalNumber,
readGeneratedFiles, and rejectUnknownKeys to locate where to insert these checks
in readGeneratedLegs.

In `@test/fixtures/continuum/receipt-family-wesley-realization-manifest.json`:
- Line 4: The fixture contains a machine-specific absolute "canonicalSchemaPath"
value which breaks portability; edit the
receipt-family-wesley-realization-manifest.json fixture to either remove the
optional "canonicalSchemaPath" field entirely or replace its value with a
repo-relative path (e.g., "./schemas/continuum-receipt-family.graphql") so the
fixture is consistent across contributors/CI and no host-specific absolute path
remains.

In `@test/unit/domain/continuum/ContinuumArtifactIngestionPolicy.test.ts`:
- Line 14: The test uses an environment-specific fixture value for
sourceSchemaPath ('~/git/continuum/...') which should be replaced with a
repo-neutral constant; update the test ContinuumArtifactIngestionPolicy.test.ts
to import or reference the shared test fixture constant (e.g.,
SCHEMA_FIXTURE_PATH or a suite-level RELATIVE_SCHEMA_PATH) and replace all
occurrences of sourceSchemaPath in the file (including the other instances
noted) with that constant so the path is repo-relative and portable across
environments.

In `@test/unit/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.test.ts`:
- Around line 276-349: Add three regression tests to the
ContinuumArtifactJsonFileAdapter test suite: (1) create a fixture JSON loaded
via ContinuumArtifactJsonFileAdapter.loadString with authority
'generated-artifact' and attempt to load a Wesley manifest JSON with authority
'generated-fixture' using loadString, asserting it throws AdapterValidationError
(shape-binding/authority mismatch); (2) add a test that constructs a sealed
Wesley manifest where manifest.artifactCount !== manifest.files.length and
assert ContinuumArtifactJsonFileAdapter.loadString throws AdapterValidationError
(ensure explicit artifactCount must match files.length); and (3) add a test that
creates a sealed Wesley manifest with generatedLegs = [] and assert loadString
throws AdapterValidationError (empty generatedLegs rejected for sealed
manifests). Use existing fixture JSON constants and the
ContinuumArtifactJsonFileAdapter class and its loadString/loadFile calls to
locate where to add these tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 47103933-1949-48c5-89f1-9178d67e2899

📥 Commits

Reviewing files that changed from the base of the PR and between 5afdd3e and e1b483e.

⛔ Files ignored due to path filters (4)
  • docs/design/0124-v17-release-blocker-dag.dot is excluded by !**/*.dot
  • docs/design/0124-v17-release-blocker-dag.svg is excluded by !**/*.svg
  • docs/design/0124-v17-release-blocker-status.csv is excluded by !**/*.csv
  • docs/design/continuum-categories.pdf is excluded by !**/*.pdf
📒 Files selected for processing (30)
  • docs/BEARING.md
  • docs/VISION.md
  • docs/design/0124-v17-release-blocker-dag.md
  • docs/design/0145-push-pr-review-merge/push-pr-review-merge.md
  • docs/design/0146-v18-continuum-compatibility-charter/v18-continuum-compatibility-charter.md
  • docs/design/0147-v18-continuum-contract-matrix/v18-continuum-contract-matrix.md
  • docs/design/0148-v18-warp-optic-realization-map/v18-warp-optic-realization-map.md
  • docs/design/0149-v18-continuum-artifact-ingestion/v18-continuum-artifact-ingestion.md
  • docs/design/continuum-categories.tex
  • docs/method/backlog/README.md
  • docs/method/backlog/WORKLOADS.md
  • docs/method/backlog/bad-code/RELEASE_TRIAGE.md
  • docs/method/backlog/v18.0.0/PROTO_echo-shaped-edge-records.md
  • docs/method/backlog/v18.0.0/PROTO_echo-shaped-node-records.md
  • docs/method/backlog/v18.0.0/README.md
  • docs/method/retro/0145-push-pr-review-merge/push-pr-review-merge.md
  • index.ts
  • src/domain/continuum/ContinuumArtifactAuthority.ts
  • src/domain/continuum/ContinuumArtifactDescriptor.ts
  • src/domain/continuum/ContinuumArtifactIngestionPolicy.ts
  • src/domain/continuum/ContinuumFamilyId.ts
  • src/domain/errors/ContinuumArtifactAuthorityError.ts
  • src/domain/errors/index.ts
  • src/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.ts
  • test/fixtures/continuum/receipt-family-generated-artifact.json
  • test/fixtures/continuum/receipt-family-wesley-realization-manifest.json
  • test/unit/domain/continuum/ContinuumArtifactIngestionPolicy.test.ts
  • test/unit/domain/errors/index.test.ts
  • test/unit/domain/index.exports.test.ts
  • test/unit/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.test.ts

Comment on lines +13 to +19
assertGeneratedAuthority(descriptor: ContinuumArtifactDescriptor): void {
if (descriptor.hasGeneratedAuthority()) {
return;
}
throw new ContinuumArtifactAuthorityError(
`Continuum family ${descriptor.familyId.toString()} must be loaded from a generated artifact or fixture, not ${descriptor.authority.toString()}`,
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Authority validation is too coarse and permits kind/authority mismatches.

Current policy accepts any “generated” authority and does not enforce the expected authority for each descriptor shape/kind. This can admit contradictory descriptors (e.g., Wesley manifest + generated-fixture, Continuum fixture + generated-artifact).

💡 Proposed tightening
+const EXPECTED_AUTHORITY_BY_KIND = Object.freeze({
+  'wesley.realization.manifest.v1': 'generated-artifact',
+  'continuum.family.fixture': 'generated-fixture',
+} as const);
+
 export default class ContinuumArtifactIngestionPolicy {
   ingest(descriptor: ContinuumArtifactDescriptor): ContinuumArtifactDescriptor {
-    this.assertGeneratedAuthority(descriptor);
+    this.assertGeneratedAuthority(descriptor);
     return descriptor;
   }

   assertGeneratedAuthority(descriptor: ContinuumArtifactDescriptor): void {
-    if (descriptor.hasGeneratedAuthority()) {
-      return;
-    }
-    throw new ContinuumArtifactAuthorityError(
-      `Continuum family ${descriptor.familyId.toString()} must be loaded from a generated artifact or fixture, not ${descriptor.authority.toString()}`,
-    );
+    const expected = EXPECTED_AUTHORITY_BY_KIND[
+      descriptor.artifactKind as keyof typeof EXPECTED_AUTHORITY_BY_KIND
+    ];
+    if (expected === undefined || descriptor.authority.toString() !== expected) {
+      throw new ContinuumArtifactAuthorityError(
+        `Continuum family ${descriptor.familyId.toString()} requires authority ${expected ?? 'known-kind-authority'} for ${descriptor.artifactKind}, not ${descriptor.authority.toString()}`,
+      );
+    }
   }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/domain/continuum/ContinuumArtifactIngestionPolicy.ts` around lines 13 -
19, assertGeneratedAuthority currently only checks
descriptor.hasGeneratedAuthority() and therefore allows mismatched
kind/authority pairs; update it to validate that the descriptor's actual
authority exactly matches the expected generated authority for its shape/kind.
In practice, inside assertGeneratedAuthority use ContinuumArtifactDescriptor's
identifying property (e.g., kind or shape) to determine the expected generated
authority (compute or call a helper like
expectedGeneratedAuthorityForKind(kind)) and then check both
descriptor.hasGeneratedAuthority() and
descriptor.authority.equals(expectedAuthority); if either fails throw the
existing ContinuumArtifactAuthorityError with a message that includes
descriptor.familyId, descriptor.kind (or shape) and the actual vs expected
authority so mismatches like Wesley manifest + generated-fixture or fixture +
generated-artifact are rejected. Ensure you reference and update
assertGeneratedAuthority, ContinuumArtifactDescriptor, and the thrown
ContinuumArtifactAuthorityError only.

Comment on lines +133 to +135
generatedBy: context.generatedBy ?? 'wesley compile',
artifactKind: context.artifactKind ?? WESLEY_REALIZATION_MANIFEST_KIND,
targets: readStringArray(source, 'targets'),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Bind authority and artifactKind to the parsed JSON shape.

context.authority and optional context.artifactKind can currently contradict the parsed payload shape, so callers can emit mismatched descriptors. Enforce shape-derived artifactKind and reject authority mismatches per shape.

Suggested fix
 export type ContinuumArtifactJsonLoadContext = {
   readonly familyId: string | ContinuumFamilyId;
   readonly authority: string | ContinuumArtifactAuthority;
   readonly sourceSchemaPath?: string;
   readonly generatedBy?: string;
-  readonly artifactKind?: string;
   readonly version?: string;
   readonly targets?: readonly string[];
   readonly witnessScope?: string;
   readonly artifactDigest?: string;
 };
@@
 function parseWesleyRealizationManifest(
   source: JsonObject,
   context: ContinuumArtifactJsonLoadContext,
 ): ContinuumArtifactDescriptorFields {
+  assertExpectedAuthority(context.authority, 'generated-artifact', 'Wesley realization manifest');
   validateWesleyManifestEnvelope(source);
   const integrity = readSealedIntegrity(source);
   const legs = readGeneratedLegs(source);
   return descriptorFields(context, {
-    ...wesleyManifestFields(source, context),
+    ...wesleyManifestFields(source),
     ...integrity,
     generatedLegs: legs.names,
     generatedFiles: legs.files,
   });
 }
@@
-function wesleyManifestFields(
-  source: JsonObject,
-  context: ContinuumArtifactJsonLoadContext,
-): DescriptorFieldSource {
+function wesleyManifestFields(source: JsonObject): DescriptorFieldSource {
   return {
     sourceSchemaPath: readRequiredString(source, 'schemaPath'),
-    generatedBy: context.generatedBy ?? 'wesley compile',
-    artifactKind: context.artifactKind ?? WESLEY_REALIZATION_MANIFEST_KIND,
+    generatedBy: 'wesley compile',
+    artifactKind: WESLEY_REALIZATION_MANIFEST_KIND,
     targets: readStringArray(source, 'targets'),
@@
 function parseContinuumFamilyFixture(
   source: JsonObject,
   context: ContinuumArtifactJsonLoadContext,
 ): ContinuumArtifactDescriptorFields {
+  assertExpectedAuthority(context.authority, 'generated-fixture', 'Continuum family fixture');
@@
   return descriptorFields(context, {
     sourceSchemaPath: readContextString(context.sourceSchemaPath, 'sourceSchemaPath'),
     generatedBy: context.generatedBy ?? CONTINUUM_FIXTURE_GENERATOR,
-    artifactKind: context.artifactKind ?? CONTINUUM_FIXTURE_KIND,
+    artifactKind: CONTINUUM_FIXTURE_KIND,
     targets: context.targets ?? [CONTINUUM_FIXTURE_TARGET],
   });
 }

Also applies to: 158-163, 166-177

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.ts` around lines
133 - 135, The parsed JSON must determine artifactKind and authority rather than
letting context override them: in ContinuumArtifactJsonFileAdapter's JSON
parsing logic (the block that sets generatedBy, artifactKind, targets using
readStringArray/readString), read the artifactKind and authority from the source
JSON shape and bind artifactKind to that value (do not default to
context.artifactKind), and validate that context.authority (if provided) matches
the parsed authority; if they mismatch, throw a validation/error. Apply the same
enforcement where similar parsing occurs (the other parsing blocks around the
indicated ranges 158-163 and 166-177).

Comment on lines +258 to +303
function readGeneratedLegs(source: JsonObject): {
readonly names: readonly string[];
readonly files: readonly string[];
} {
const generatedLegs = requireJsonObject(source['generatedLegs'], 'Wesley realization manifest generatedLegs');
const names = Object.freeze(Object.keys(generatedLegs).sort());
const files: string[] = [];
for (const name of names) {
const leg = requireJsonObject(generatedLegs[name], `Wesley generated leg "${name}"`);
rejectUnknownKeys(
leg,
['outDir', 'schemaHash', 'sourceHash', 'targets', 'artifactCount', 'files'],
`Wesley generated leg "${name}"`,
);
readRequiredString(leg, 'outDir');
readRequiredString(leg, 'schemaHash');
readRequiredString(leg, 'sourceHash');
readOptionalStringArray(leg, 'targets');
readOptionalNumber(leg, 'artifactCount');
for (const path of readGeneratedFiles(leg, name)) {
files.push(path);
}
}
return { names, files: Object.freeze(files.sort()) };
}

/** Reads generated file entries from one Wesley generated leg. */
function readGeneratedFiles(source: JsonObject, legName: string): readonly string[] {
const value = source['files'];
if (value === undefined) {
return [];
}
if (!Array.isArray(value)) {
throw new AdapterValidationError(`Wesley generated leg "${legName}" field "files" must be an array`);
}
const files: string[] = [];
for (const entry of value) {
const file = requireJsonObject(entry, `Wesley generated leg "${legName}" file`);
rejectUnknownKeys(file, ['path', 'size', 'contentHash', 'signature'], `Wesley generated leg "${legName}" file`);
files.push(readRequiredString(file, 'path'));
readRequiredNumber(file, 'size');
readRequiredString(file, 'contentHash');
readRequiredString(file, 'signature');
}
return Object.freeze(files);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject empty/inconsistent generated-leg inventory in sealed Wesley manifests.

readGeneratedLegs accepts {} and never validates artifactCount against files.length, so sealed manifests can claim inventory that does not match file evidence.

Suggested fix
 function readGeneratedLegs(source: JsonObject): {
   readonly names: readonly string[];
   readonly files: readonly string[];
 } {
   const generatedLegs = requireJsonObject(source['generatedLegs'], 'Wesley realization manifest generatedLegs');
   const names = Object.freeze(Object.keys(generatedLegs).sort());
+  if (names.length === 0) {
+    throw new AdapterValidationError('Wesley realization manifest must include at least one generated leg');
+  }
   const files: string[] = [];
   for (const name of names) {
@@
-    readOptionalNumber(leg, 'artifactCount');
-    for (const path of readGeneratedFiles(leg, name)) {
+    const artifactCount = readOptionalNumber(leg, 'artifactCount');
+    const legFiles = readGeneratedFiles(leg, name);
+    if (artifactCount !== undefined && artifactCount !== legFiles.length) {
+      throw new AdapterValidationError(
+        `Wesley generated leg "${name}" artifactCount must equal files length`,
+      );
+    }
+    if (artifactCount !== undefined && artifactCount > 0 && legFiles.length === 0) {
+      throw new AdapterValidationError(
+        `Wesley generated leg "${name}" with positive artifactCount must include files`,
+      );
+    }
+    for (const path of legFiles) {
       files.push(path);
     }
   }
   return { names, files: Object.freeze(files.sort()) };
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function readGeneratedLegs(source: JsonObject): {
readonly names: readonly string[];
readonly files: readonly string[];
} {
const generatedLegs = requireJsonObject(source['generatedLegs'], 'Wesley realization manifest generatedLegs');
const names = Object.freeze(Object.keys(generatedLegs).sort());
const files: string[] = [];
for (const name of names) {
const leg = requireJsonObject(generatedLegs[name], `Wesley generated leg "${name}"`);
rejectUnknownKeys(
leg,
['outDir', 'schemaHash', 'sourceHash', 'targets', 'artifactCount', 'files'],
`Wesley generated leg "${name}"`,
);
readRequiredString(leg, 'outDir');
readRequiredString(leg, 'schemaHash');
readRequiredString(leg, 'sourceHash');
readOptionalStringArray(leg, 'targets');
readOptionalNumber(leg, 'artifactCount');
for (const path of readGeneratedFiles(leg, name)) {
files.push(path);
}
}
return { names, files: Object.freeze(files.sort()) };
}
/** Reads generated file entries from one Wesley generated leg. */
function readGeneratedFiles(source: JsonObject, legName: string): readonly string[] {
const value = source['files'];
if (value === undefined) {
return [];
}
if (!Array.isArray(value)) {
throw new AdapterValidationError(`Wesley generated leg "${legName}" field "files" must be an array`);
}
const files: string[] = [];
for (const entry of value) {
const file = requireJsonObject(entry, `Wesley generated leg "${legName}" file`);
rejectUnknownKeys(file, ['path', 'size', 'contentHash', 'signature'], `Wesley generated leg "${legName}" file`);
files.push(readRequiredString(file, 'path'));
readRequiredNumber(file, 'size');
readRequiredString(file, 'contentHash');
readRequiredString(file, 'signature');
}
return Object.freeze(files);
}
function readGeneratedLegs(source: JsonObject): {
readonly names: readonly string[];
readonly files: readonly string[];
} {
const generatedLegs = requireJsonObject(source['generatedLegs'], 'Wesley realization manifest generatedLegs');
const names = Object.freeze(Object.keys(generatedLegs).sort());
if (names.length === 0) {
throw new AdapterValidationError('Wesley realization manifest must include at least one generated leg');
}
const files: string[] = [];
for (const name of names) {
const leg = requireJsonObject(generatedLegs[name], `Wesley generated leg "${name}"`);
rejectUnknownKeys(
leg,
['outDir', 'schemaHash', 'sourceHash', 'targets', 'artifactCount', 'files'],
`Wesley generated leg "${name}"`,
);
readRequiredString(leg, 'outDir');
readRequiredString(leg, 'schemaHash');
readRequiredString(leg, 'sourceHash');
readOptionalStringArray(leg, 'targets');
const artifactCount = readOptionalNumber(leg, 'artifactCount');
const legFiles = readGeneratedFiles(leg, name);
if (artifactCount !== undefined && artifactCount !== legFiles.length) {
throw new AdapterValidationError(
`Wesley generated leg "${name}" artifactCount must equal files length`,
);
}
if (artifactCount !== undefined && artifactCount > 0 && legFiles.length === 0) {
throw new AdapterValidationError(
`Wesley generated leg "${name}" with positive artifactCount must include files`,
);
}
for (const path of legFiles) {
files.push(path);
}
}
return { names, files: Object.freeze(files.sort()) };
}
/** Reads generated file entries from one Wesley generated leg. */
function readGeneratedFiles(source: JsonObject, legName: string): readonly string[] {
const value = source['files'];
if (value === undefined) {
return [];
}
if (!Array.isArray(value)) {
throw new AdapterValidationError(`Wesley generated leg "${legName}" field "files" must be an array`);
}
const files: string[] = [];
for (const entry of value) {
const file = requireJsonObject(entry, `Wesley generated leg "${legName}" file`);
rejectUnknownKeys(file, ['path', 'size', 'contentHash', 'signature'], `Wesley generated leg "${legName}" file`);
files.push(readRequiredString(file, 'path'));
readRequiredNumber(file, 'size');
readRequiredString(file, 'contentHash');
readRequiredString(file, 'signature');
}
return Object.freeze(files);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.ts` around lines
258 - 303, readGeneratedLegs currently accepts empty generatedLegs and doesn't
validate artifactCount against the actual files, allowing inconsistent sealed
manifests; update readGeneratedLegs (and readGeneratedFiles usage) so that after
calling readOptionalNumber(leg, 'artifactCount') and collecting files via
readGeneratedFiles(leg, name) you validate: if artifactCount is present and not
equal to files.length throw an AdapterValidationError with a clear message
referencing the leg name, and additionally reject an entirely empty
generatedLegs map by throwing an AdapterValidationError when names.length === 0;
use the existing AdapterValidationError type and the functions
readOptionalNumber, readGeneratedFiles, and rejectUnknownKeys to locate where to
insert these checks in readGeneratedLegs.

{
"kind": "wesley.realization.manifest.v1",
"schemaPath": "schemas/continuum-receipt-family.graphql",
"canonicalSchemaPath": "/Users/james/git/continuum/schemas/continuum-receipt-family.graphql",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace machine-specific canonicalSchemaPath in shared fixture.

This absolute path is host-specific and makes the fixture non-portable across contributors/CI. Use a repo-relative value or remove the optional field in this fixture.

Suggested fix
-  "canonicalSchemaPath": "/Users/james/git/continuum/schemas/continuum-receipt-family.graphql",
+  "canonicalSchemaPath": "schemas/continuum-receipt-family.graphql",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"canonicalSchemaPath": "/Users/james/git/continuum/schemas/continuum-receipt-family.graphql",
"canonicalSchemaPath": "schemas/continuum-receipt-family.graphql",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/fixtures/continuum/receipt-family-wesley-realization-manifest.json` at
line 4, The fixture contains a machine-specific absolute "canonicalSchemaPath"
value which breaks portability; edit the
receipt-family-wesley-realization-manifest.json fixture to either remove the
optional "canonicalSchemaPath" field entirely or replace its value with a
repo-relative path (e.g., "./schemas/continuum-receipt-family.graphql") so the
fixture is consistent across contributors/CI and no host-specific absolute path
remains.

function makeDescriptor(authority: string): ContinuumArtifactDescriptor {
return new ContinuumArtifactDescriptor({
familyId: 'receipt-family',
sourceSchemaPath: '~/git/continuum/schemas/continuum-receipt-family.graphql',
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use a repo-neutral schema path fixture string.

The ~/git/continuum/... path is environment-shaped and makes fixture semantics less portable. Replace with a stable repo-relative token/path constant used across the suite.

🧩 Suggested cleanup
+const RECEIPT_SCHEMA_PATH = 'schemas/continuum/continuum-receipt-family.graphql';
+
 function makeDescriptor(authority: string): ContinuumArtifactDescriptor {
   return new ContinuumArtifactDescriptor({
     familyId: 'receipt-family',
-    sourceSchemaPath: '~/git/continuum/schemas/continuum-receipt-family.graphql',
+    sourceSchemaPath: RECEIPT_SCHEMA_PATH,
@@
-      sourceSchemaPath: '~/git/continuum/schemas/continuum-receipt-family.graphql',
+      sourceSchemaPath: RECEIPT_SCHEMA_PATH,
@@
-      sourceSchemaPath: '~/git/continuum/schemas/continuum-receipt-family.graphql',
+      sourceSchemaPath: RECEIPT_SCHEMA_PATH,

Also applies to: 77-77, 104-104, 113-113, 135-135, 145-145

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/unit/domain/continuum/ContinuumArtifactIngestionPolicy.test.ts` at line
14, The test uses an environment-specific fixture value for sourceSchemaPath
('~/git/continuum/...') which should be replaced with a repo-neutral constant;
update the test ContinuumArtifactIngestionPolicy.test.ts to import or reference
the shared test fixture constant (e.g., SCHEMA_FIXTURE_PATH or a suite-level
RELATIVE_SCHEMA_PATH) and replace all occurrences of sourceSchemaPath in the
file (including the other instances noted) with that constant so the path is
repo-relative and portable across environments.

Comment on lines +276 to +349
it('rejects local mirrors before they become authority', async () => {
const adapter = new ContinuumArtifactJsonFileAdapter();

await expect(adapter.loadFile(generatedFixturePath, localMirrorContext)).rejects.toThrow(ContinuumArtifactAuthorityError);
});

it('rejects self-attested authority fields inside artifact JSON', () => {
const adapter = new ContinuumArtifactJsonFileAdapter();

expect(() => adapter.loadString(selfAttestedFixtureJson, fixtureContext)).toThrow(AdapterValidationError);
});

it('wraps invalid JSON syntax as adapter validation failure', () => {
const adapter = new ContinuumArtifactJsonFileAdapter();

expect(() => adapter.loadString('{ "objectTypes": [', fixtureContext)).toThrow(AdapterValidationError);
});

it('rejects unsupported top-level JSON shapes', () => {
const adapter = new ContinuumArtifactJsonFileAdapter();

expect(() => adapter.loadString('null', fixtureContext)).toThrow(AdapterValidationError);
expect(() => adapter.loadString('[]', fixtureContext)).toThrow(AdapterValidationError);
expect(() => adapter.loadString('{ "familyId": "receipt-family" }', fixtureContext)).toThrow(AdapterValidationError);
});

it('rejects unknown fixture keys and malformed nested entries', () => {
const adapter = new ContinuumArtifactJsonFileAdapter();

expect(() => adapter.loadString(unknownFixtureFieldJson, fixtureContext)).toThrow(AdapterValidationError);
expect(() => adapter.loadString(invalidOperationJson, fixtureContext)).toThrow(AdapterValidationError);
expect(() => adapter.loadString(emptyOperationsJson, fixtureContext)).toThrow(AdapterValidationError);
expect(() => adapter.loadString(invalidFootprintsJson, fixtureContext)).toThrow(AdapterValidationError);
});

it('accepts fixture artifacts with omitted optional footprints', () => {
const adapter = new ContinuumArtifactJsonFileAdapter();

expect(adapter.loadString(fixtureWithoutFootprintsJson, fixtureContext).artifactKind).toBe('continuum.family.fixture');
});

it('requires source schema context for fixture artifacts', () => {
const adapter = new ContinuumArtifactJsonFileAdapter();
const contextWithoutSchemaPath: ContinuumArtifactJsonLoadContext = {
familyId: 'receipt-family',
authority: 'generated-fixture',
};

expect(() => adapter.loadString(typeMapFixtureJson, contextWithoutSchemaPath)).toThrow(AdapterValidationError);
});

it('rejects unsealed Wesley realization manifests', () => {
const adapter = new ContinuumArtifactJsonFileAdapter();

expect(() => adapter.loadString(unsealedWesleyManifestJson, artifactContext)).toThrow(AdapterValidationError);
});

it('rejects malformed Wesley realization manifest numbers and targets', () => {
const adapter = new ContinuumArtifactJsonFileAdapter();

expect(() => adapter.loadString(invalidWesleyArtifactCountJson, artifactContext)).toThrow(AdapterValidationError);
expect(() => adapter.loadString(invalidWesleyGeneratedFilesJson, artifactContext)).toThrow(AdapterValidationError);
expect(() => adapter.loadString(invalidWesleyTargetsJson, artifactContext)).toThrow(AdapterValidationError);
expect(() => adapter.loadString(invalidWesleyTargetEntryJson, artifactContext)).toThrow(AdapterValidationError);
});

it('accepts Wesley generated legs before the compiler writes file inventory', () => {
const adapter = new ContinuumArtifactJsonFileAdapter();
const descriptor = adapter.loadString(wesleyManifestWithoutGeneratedFilesJson, artifactContext);

expect(descriptor.generatedLegs).toEqual(['warpTtd']);
expect(descriptor.generatedFiles).toEqual([]);
});
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add regression tests for shape-binding and generated inventory parity.

This suite still misses critical cases: (1) fixture loaded with generated-artifact authority and Wesley manifest loaded with generated-fixture authority should fail, (2) explicit artifactCount must match files.length, and (3) empty generatedLegs should fail for sealed manifests.

As per coding guidelines **/*.test.{ts,tsx}: Touched code in refactor slices must reach 100% test coverage before the slice is considered done.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/unit/infrastructure/adapters/ContinuumArtifactJsonFileAdapter.test.ts`
around lines 276 - 349, Add three regression tests to the
ContinuumArtifactJsonFileAdapter test suite: (1) create a fixture JSON loaded
via ContinuumArtifactJsonFileAdapter.loadString with authority
'generated-artifact' and attempt to load a Wesley manifest JSON with authority
'generated-fixture' using loadString, asserting it throws AdapterValidationError
(shape-binding/authority mismatch); (2) add a test that constructs a sealed
Wesley manifest where manifest.artifactCount !== manifest.files.length and
assert ContinuumArtifactJsonFileAdapter.loadString throws AdapterValidationError
(ensure explicit artifactCount must match files.length); and (3) add a test that
creates a sealed Wesley manifest with generatedLegs = [] and assert loadString
throws AdapterValidationError (empty generatedLegs rejected for sealed
manifests). Use existing fixture JSON constants and the
ContinuumArtifactJsonFileAdapter class and its loadString/loadFile calls to
locate where to add these tests.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant