Skip to content

feat(harness): add durable build planning contracts - #784

Open
ynadge wants to merge 4 commits into
mainfrom
conductor/e4-sap-3067-contracts-v1
Open

feat(harness): add durable build planning contracts#784
ynadge wants to merge 4 commits into
mainfrom
conductor/e4-sap-3067-contracts-v1

Conversation

@ynadge

@ynadge ynadge commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Primary change type

  • Bug fix
  • Documentation
  • Feature
  • Tests
  • Dependency update
  • Maintenance or refactor

Problem and motivation

E2 persists exact architecture proposal and revision history, but its project build-plan pointer had no durable delivery contract behind it. E4 needs immutable, exact-source-bound plans, focused agent briefs, stable planning assignments, and structured builder submissions without copying the architecture graph or relying on conversation transcripts.

Summary and scope

Adds strict versioned build-planning contracts and codecs; canonical semantic and full-record SHA-256 digests; exact proposal/revision source resolution; bounded deterministic completeness, relationship-aware dependency evidence, freshness, and eligibility validation; and crash-atomic build-planning history inside the existing per-project Agent Map aggregate. Stable agent assignment/brief identities, current-plan CAS for compiled briefs, request tombstones, explicit history quota errors, assignment/submission provenance integrity, and raw-content-keyed integrity caching are covered by persistence tests.

Relationship validation now projects E2 actor-oriented reads edges into effective data-flow direction and validates producer/consumer paths through artifacts and resources. This lets Research -> writes -> ResearchReport plus Marketing -> reads -> ResearchReport prove provides-input and consumes-output dependencies while preserving ownership-root, direction, and exact-contract checks; generic uses edges remain shared-resource evidence rather than producer/consumer proof.

The package-root export is intentionally limited to exact-source references, stable plan/brief/assignment handoff references, the builder submission contract, their complete transitive branded/member type closure, and the shared source comparator required by downstream hosts. A package-root consumer test constructs and consumes the whole supported v1 handoff without subpath imports. Full persistence/compiler records remain internal. Authoring MCP tools, brief compilation, planning-session fan-out, repositories, deployment, and implementation authorization remain out of scope.

Related work

Related issue or discussion:

Closes: SAP-3067

Validation

pnpm --filter @sapiom/harness exec vitest run src/public-build-plan-entrypoint.test.ts src/shared/build-plan-codec.test.ts src/core/build-plan-canonicalization.test.ts src/core/architecture-source-resolver.test.ts src/core/build-plan-contract-validator.test.ts src/core/build-plan-store.test.ts src/core/agent-map-workspace-store.test.ts — passed (7 files, 46 tests)
pnpm --filter @sapiom/harness typecheck — passed
pnpm --filter @sapiom/harness lint — passed
pnpm --filter @sapiom/harness build — passed (existing Vite chunk-size/dynamic-import warnings only)
pnpm --filter @sapiom/harness test — passed (210 regular files / 3,339 tests; 3 performance files / 10 tests)
pnpm changeset status --since=origin/main — passed
pnpm pr-labeler:check — passed (21 tests and formatting)
node scripts/pr-label-classifier.mjs validation — passed (complete feature template)
git diff --check origin/main — passed

Tests and documentation

Added contract/codec malformed fixtures, digest vectors, exact proposal/revision identity cases, populated E2 migration, current-plan CAS regression, ownership-root dependency and port evidence cases, golden writes/reads flow through an ownerless artifact with valid input-port linkage and wrong-direction/wrong-contract negatives, a package-root handoff consumer, same-size/restored-mtime tamper detection, idempotency tombstones, explicit history limits, corruption/provenance detection, restart/history, locking, pointer consistency, and atomic-write coverage. Documentation is N/A because this ticket adds an internal persistence foundation with no user-facing workflow; release and downgrade behavior is documented in the Changeset and compatibility section.

Compatibility and release impact

  • Breaking or externally visible changes: Agent Map workspace files migrate in place from aggregate storage schema v1 to v2 while preserving E2 proposal history and receipts. The migration is downgrade-incompatible: older harness releases cannot read a workspace after v2 has been written. The new package-root type surface is deliberately limited to downstream handoff contracts while exporting their complete transitive construction/consumption types.
  • Changeset: Added a minor @sapiom/harness Changeset with the v2 downgrade limitation.

Security

  • I have not included secrets, credentials, private data, or unsanitized logs.
  • This pull request does not publicly disclose a suspected vulnerability. I
    will follow the
    Security Policy for
    private reporting.

AI assistance

  • I did not use AI assistance for this change.
  • I used AI assistance and have described it below.

OpenAI Codex implemented and revised the contracts, persistence primitives, validation, and tests. I inspected the complete diff against origin/main and verified it with focused tests, typecheck, lint, package build, the full harness test/performance suites, Changesets status, and the repository PR-template classifier.

Checklist

  • I read CONTRIBUTING.md, and this contribution follows the direct-PR or issue-first policy.
  • This pull request addresses one focused problem and contains no unrelated cleanup.
  • I added or updated tests, or explained above why tests are not applicable.
  • I ran the relevant build, typecheck, lint, and test commands, or explained
    any N/A checks above.
  • I updated documentation for user-facing changes, or marked it N/A above.
  • I added a Changeset for a published-package change, or explained why it is not applicable.
  • I can explain and maintain every submitted change, including any AI-assisted work.

Define strict versioned plan, brief, assignment, and submission records over exact Agent Map sources. Add canonical semantic and record digests, aggregate migration and integrity checks, exact-source resolution, validators, and crash-atomic persistence primitives.

Closes: SAP-3067
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Follow-up review — PR #784 (delta since 4223343)

Earlier findings: all six fixed

Private Linear/Conductor URLs dropped from the body (Closes: SAP-3067); minor changeset added
with the v2 downgrade note and clean of confidential copy; export type * narrowed to six named
types; digest re-hashing moved out of parseAggregate into assertBuildPlanningIntegrity;
the 1024 cap now raises a dedicated BuildPlanStoreLimitError instead of malformed_state;
all three JSON.stringify comparators replaced by one order-independent
architectureSourceRefsEqual. Nothing in the earlier round was wrong.

New: the narrowed export set is not usable by the hosts it targets

packages/harness/src/index.ts:30-41 exports six handoff types plus
architectureSourceRefsEqual, but every type they are built from stays internal, and
package.json exports is "." only — no subpath to reach shared/build-plan.js.
So a consumer holding a BuilderPlanningSubmission cannot name ImplementationPlanStep,
PlanningRisk, PlanningQuestion, or BuilderPlanningSubmissionId, and cannot build an
ArchitectureSourceRef to feed the comparator without as casts through the branded
GraphDigest / MapProposalId+AgentMapRevisionId fields. Export the transitive
id/digest/member types (or a parse helper), or keep the whole module internal until E4's
callers land.

New: the integrity cache keys on stat, not content

agent-map-workspace-store.ts:392-397 stats the file after readFile, so the cached
dev:ino:size:mtimeNs can describe bytes that were never parsed or verified; once cached,
assertBuildPlanningIntegrity never runs again for that file in the process. An in-place
edit that preserves size and mtime (coarse-granularity filesystems, restored utimes) is
invisible to the digests that exist to catch exactly that. Cheaper and exact: hash the raw
string you already read.

Nit: build-plan-contract-validator.ts:277!supported || !contractsLinked is redundant,
supported already requires contractsLinked.

Verdict: Approve with comments — the export surface is the one thing worth settling before
publish; the rest is now solid.

Expose the complete explicit v1 handoff type closure and key planning integrity verification by the raw bytes read from disk.

Closes: SAP-3067

ynadge commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the follow-up review in 48dc1c5:

  • Public v1 surface: kept the explicit export list and added every transitive ID, digest, and member type needed by the six handoff records. public-build-plan-entrypoint.test.ts imports only the package root and constructs/consumes the supported context, refs, source variants, and submission.
  • Integrity cache: replaced the dev/ino/size/mtime key with SHA-256 of the exact raw string read (and exact serialized string written). The regression changes persisted bytes without changing length, restores the prior mtime, confirms the metadata tuple is unchanged, and verifies the live store rejects the tampered record.
  • Review cleanup: removed the redundant !contractsLinked guard. The ResearchReport golden fixture is now an ownerless E2 artifact and remains valid as a writes/reads carrier path.

Fresh validation: focused 7 files / 46 tests, typecheck, lint, build, full harness 210 files / 3,339 tests, performance 3 files / 10 tests, Changeset status, PR labeler (21 tests), formatter, and diff checks all passed.

@sapiom sapiom deleted a comment from github-actions Bot Sep 3, 2026
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