You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Project agents need one durable shared map/build-plan history that supports concurrent universal authoring without planner/builder authority, approval gates, or silent overwrites. SAP-3149 replaces the conflicting historical revision/digest models with one role-neutral contract and migrates the deployed E1/E2 state directly to it.
Summary and scope
Adds one canonical map-version, graph-content-digest, plan-version, actor, and reserved neutral brief-history vocabulary with pinned semantic and record digest vectors.
Migrates deployed E1/E2 workspace aggregates directly to final storage schema 2, with immutable histories, exact pointers, integrity validation, locking, quotas, request receipts/tombstones, atomic replacement, and append-only restore foundations.
Adds pure build_plan_read, build_plan_validate, build_plan_apply, and build_plan_rebase operations with deterministic IDs, replay/no-op semantics, same-source stale-disjoint merging, stable conflicts, and explicit map rebase resolutions.
Registers all four tools for every ordinary project session using only capability-derived project/user/session scope, and emits bounded content-free operation telemetry.
Reserves empty append-only brief histories keyed by neutral canonical-workstream or nested ad-hoc-delegation scopes; plan authoring does not invoke a compiler.
Intentionally out of scope: focused brief compilation/projection (SAP-3150), subsession coordination (SAP-3151), cutover/archive work (SAP-3152), and any planner/builder or approval authority.
Stacked on conductor/sap-3148-unified-project-agents at 5d00c55925d1907670bed6e885384b25eb775a73.
Validation
pnpm build — passed (18 workspace packages)
pnpm typecheck — passed (18 workspace packages)
pnpm lint — passed; existing unrelated warnings only, no errors
pnpm --filter @sapiom/harness test — passed after review fixes (216 files / 3,505 tests; 3 perf files / 10 tests)
pnpm --filter @sapiom/harness exec vitest run src/core/build-plan-service.test.ts src/core/agent-map-proposal-service.test.ts src/server/agent-map-mcp.test.ts — passed (3 files / 38 tests)
pnpm --filter @sapiom/harness exec vitest run src/core/build-plan-service.test.ts src/server/agent-map-mcp.test.ts src/server/agent-map-mcp-wiring.test.ts src/public-build-plan-entrypoint.test.ts src/core/build-plan-schema.test.ts — passed (5 files / 33 tests)
git diff --check — passed
pnpm test — incomplete: all reached packages passed until one existing @sapiom/agent-core test failed because this VM still permits directory reads after chmod 0111
pnpm --filter @sapiom/agent-core exec jest src/bundle-error.spec.ts --runInBand — same single environment-specific failure reproduced; SAP-3149 has no agent-core diff
Tests and documentation
Adds golden digest, strict codec, migration, corruption, ancestry, restore, CAS, replay, tombstone, quota, locking/atomic failure, stale-disjoint/conflict, explicit rebase, neutral brief-scope, MCP discovery/invocation, isolation, telemetry, and public-entrypoint coverage. Updates the harness README and adds docs/shared-build-plan.md.
Compatibility and release impact
Breaking or externally visible changes: Existing E1/E2 Agent Map state migrates directly to the final role-neutral schema. The current E2 proposal projection remains compatible while immutable map versions become the sole stored topology. Every project session gains four build-plan tools.
Changeset: Added a minor @sapiom/harness changeset.
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 generated and edited the contracts, persistence/service/tool implementation, tests, and documentation. I reviewed the resulting diff and verified it with focused harness tests, the complete harness suite, root build/typecheck/lint, and the root test attempt documented above.
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.
1. Breaking public type change shipped as a minor changeset
packages/harness/src/shared/agent-map.ts:353 replaces the exported ProposalActor
interface with ProjectAgentActorRef, dropping the role and assignment fields:
ProposalActor is re-exported from the package root (src/index.ts:38), and it is the
type of ProposalOperationRecord.actor / MapChangeProposal.history[].actor. Any pinned
consumer that reads record.actor.role or record.actor.assignment — or that constructs a ProposalActor literal — stops compiling on upgrade. The runtime payload of GET /api/agent-map loses the same two fields.
The changeset (.changeset/neutral-shared-plan-versions.md) is minor with no Breaking
heading and no migration note. Either mark it breaking with a migration note, or keep role/assignment as @deprecated optional fields for one release and remove them later.
2. build_plan_rebase rejects (or mis-scopes) any request with two or more removals
packages/harness/src/core/build-plan-service.ts:506-535. interim is computed once
before the removal loop, so its diagnostic paths (assignments[N], repositoryIntents[N], assignments[N].dependencies[M]) index the pre-loop content. Inside the loop, content is
reassigned on every successful removal, but the index is re-derived from the mutated
array:
constassignmentIndex=content.assignments.findIndex(({ id })=>id===resolution.assignmentId);constrelevant=interim.some(({ severity, path })=>severity==="error"&&path.startsWith(`assignments[${assignmentIndex}]`));
Failure scenario: a map rebase invalidates assignments at original indices 0 and 2, and the
caller supplies both remove-assignment resolutions. The first removal succeeds; the second
now resolves to index 1, checks interim for an error at assignments[1] (the still-valid
surviving assignment), finds none, and is never added to used. Line 536 then throws invalid_rebase_resolution even though both resolutions were correct and required — the plan
can never be rebased off that map version. The inverse also happens: after a shift, a
resolution can be accepted on the strength of an unrelated assignment's error.
Match resolutions to diagnostics by entity id, not by array position, or recompute
diagnostics after each removal. build-plan-service.test.ts:267 only exercises a single
removal, so the suite does not catch this.
3. Malformed build_plan_read selectors surface as internal_error / recovery: "retry"
packages/harness/src/server/agent-map-mcp-tools.ts:229 calls parseBuildPlanReadRequest
in the tool handler, outside the service. buildPlanReadToolInputSchema
(core/build-plan-schema.ts:143) intentionally has planId/versionId/semanticDigest
optional, so { kind: "exact" } and { kind: "current", planId: "plan_…" } both pass SDK
validation and reach the handler. The raw ZodError is not a BuildPlanServiceError, so errorResult falls through to { code: "internal_error", recovery: "retry" } — the calling
agent is told to retry an input that can never succeed, instead of getting the malformed_input / recovery: "correct" that BuildPlanService.read already produces
(build-plan-service.ts:316). Drop the handler-side parse and let the service own it; the
service re-parses anyway, so this is also a redundant pass. No test covers a malformed
build-plan selector.
4. Plan history quota has no recovery path
BUILD_PLAN_VERSION_HISTORY_LIMIT = 1_024 (shared/build-plan.ts:14) is enforced in commit (build-plan-service.ts:568) by throwing quota_exceeded, with no trimming,
archival, or compaction anywhere. Receipts get eviction-to-tombstone; plan versions get
nothing. On the 1,025th semantic edit every build_plan_apply and build_plan_rebase for
that project fails permanently, and errorResult maps quota_exceeded to recovery: "retry" — an infinite retry loop for an agent. docs/shared-build-plan.md
documents the immutable-history contract but never mentions the ceiling or what a caller
should do at it.
Verdict: request changes — findings 1 and 2 must land before merge (a breaking public
type under a minor bump, and a rebase path that is broken for the multi-resolution case
it exists to serve).
Round-1 findings 1, 2 and 3 are fixed: the changeset now carries a Breaking heading
with a migration note (minor is the correct breaking bump for 0.14.0), rebase
resolutions are matched by entity id instead of array index and the multi-removal case is
covered by a test, and build_plan_read no longer parses in the handler so malformed
selectors return malformed_input / recovery: "correct" (tested).
1. New — manual_intervention is now returned for a caller-correctable quota error
packages/harness/src/server/agent-map-mcp-tools.ts:97 maps everyquota_exceeded to recovery: "manual_intervention", but that code has three throw sites. One of them, build-plan-service.ts:197, fires when a single build_plan_apply registers more client
refs than BUILD_PLAN_ID_MAPPING_LIMIT — an oversized request, not an exhausted project.
An agent that submits a large plan is now told an operator must intervene, so it stops,
when splitting the batch would have worked immediately; "correct" is the right signal
there. Give the mapping-limit throw its own code (or an error.details discriminator) and
reserve manual_intervention for the history/receipt ceilings.
2. Round-1 finding 4 only half fixed — the map-version ceiling still retries forever
packages/harness/src/core/agent-map-proposal-service.ts:294 hits the same 1,024 BUILD_PLAN_VERSION_HISTORY_LIMIT and throws AgentMapWorkspaceStoreError("storage_unavailable"), which agent-map-mcp-tools.ts:100 maps to recovery: "retry". A project whose map history is
permanently full therefore gets a transient-sounding storage error and an infinite retry
loop — exactly the behaviour the plan-side fix removed — and it contradicts the new docs/shared-build-plan.md:39-44 paragraph, which states the bound is terminal and
operator-resolved. Surface it as a quota error with the same terminal recovery, and say in
the doc that map versions share the bound.
Note: I could not execute the harness tests in this environment (command approval), so the
fixes above are assessed by reading the diff, not by a green run.
Verdict: approve with comments — both remaining items are error-signalling defects, not
data-integrity ones; neither blocks merge if you'd rather land them as a follow-up.
Both round-2 findings are fixed: the ID-mapping ceiling now throws its own request_too_large code mapped to recovery: "correct" (tested at the service and MCP
layers), and the map-version ceiling throws AgentMapProposalQuotaError → quota_exceeded / manual_intervention with a pre-mutation, no-write test and a doc
update. Nothing the earlier rounds said was wrong.
1. New — mapOperationHistory is the one history with no bound at all
packages/harness/src/core/agent-map-proposal-service.ts:303 appends one record per
accepted operation and nothing ever trims it. There is no limit constant for it
(shared/build-plan.ts:14-18 bounds map versions, plan versions, receipts and
tombstones), and agent-map-aggregate-migration.ts:251 validates the length of every other collection but skips this one. Unlike mapVersions, it also grows on
digest-unchanged proposals, which take the early-return path at line 308.
Failure scenario: a long-lived project accumulates operation records without limit in the
single aggregate JSON that every agent_map_propose reads, structuredClones and
rewrites, while lines 144/150/162/287 scan it linearly per request — latency and file size
degrade with no ceiling and no terminal signal, and the migration validator will accept an
aggregate of any size. This directly contradicts docs/shared-build-plan.md:39-44, which
now tells readers histories are bounded at 1,024 and exhaustion is terminal. Either bound
and classify it like the others, or say in the doc that operation records are unbounded.
2. request_too_large is agent-facing but undocumented
recovery: "correct" tells the agent to fix its request, but neither docs/shared-build-plan.md nor the README mentions BUILD_PLAN_ID_MAPPING_LIMIT (128
client refs per request) or the new code, and error.details carries only affectedPaths: ["operations.0.content"] — no limit value. The agent has nothing to
correct against. Add the limit to the doc's bounds paragraph.
Nit: agent-map-workspace-store.ts:318,330 still throw storage_unavailable → retry
for the brief-history and receipt ceilings; unreachable until SAP-3150, but same defect.
Tests were not runnable here (command approval), so this is a read of the diff.
Verdict: approve with comments — finding 1 is a durability/latency gap, not a
correctness break, and finding 2 is a doc line.
Superseded by the maintainer-authorized 15-part Agent Map review stack. This PR is closed without merging; its branch and review history remain preserved.
The complete testing branch remains fix/studio-onboarding-followups. Full stack: #819 through #834. Final hosted-review corrections and Mac journey validation are continuing on those same replacement PRs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Primary change type
Problem and motivation
Project agents need one durable shared map/build-plan history that supports concurrent universal authoring without planner/builder authority, approval gates, or silent overwrites. SAP-3149 replaces the conflicting historical revision/digest models with one role-neutral contract and migrates the deployed E1/E2 state directly to it.
Summary and scope
build_plan_read,build_plan_validate,build_plan_apply, andbuild_plan_rebaseoperations with deterministic IDs, replay/no-op semantics, same-source stale-disjoint merging, stable conflicts, and explicit map rebase resolutions.Intentionally out of scope: focused brief compilation/projection (SAP-3150), subsession coordination (SAP-3151), cutover/archive work (SAP-3152), and any planner/builder or approval authority.
Related work
Related issue or discussion: SAP-3149 — Add neutral shared plan versions and universal authoring
Stacked on
conductor/sap-3148-unified-project-agentsat5d00c55925d1907670bed6e885384b25eb775a73.Validation
Tests and documentation
Adds golden digest, strict codec, migration, corruption, ancestry, restore, CAS, replay, tombstone, quota, locking/atomic failure, stale-disjoint/conflict, explicit rebase, neutral brief-scope, MCP discovery/invocation, isolation, telemetry, and public-entrypoint coverage. Updates the harness README and adds
docs/shared-build-plan.md.Compatibility and release impact
@sapiom/harnesschangeset.Security
AI assistance
OpenAI Codex generated and edited the contracts, persistence/service/tool implementation, tests, and documentation. I reviewed the resulting diff and verified it with focused harness tests, the complete harness suite, root build/typecheck/lint, and the root test attempt documented above.
Checklist
CONTRIBUTING.md, and this contribution follows the direct-PR or issue-first policy.