Skip to content

Implement bounded context issuance and evidence for #179 - #198

Merged
Joncallim merged 408 commits into
architecture/issue-178-filesystem-grant-recoveryfrom
architecture/issue-179-context-packet-evidence
Jul 30, 2026
Merged

Implement bounded context issuance and evidence for #179#198
Joncallim merged 408 commits into
architecture/issue-178-filesystem-grant-recoveryfrom
architecture/issue-179-context-packet-evidence

Conversation

@Joncallim

@Joncallim Joncallim commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Status

PR #198 remains OPEN and DRAFT at exact head b1c99d6cd5cc3906dc453fd7f6e1df8d58036534, with tree 1eb934ef85754a1408028277d9f3433d57d16d57. Its base is architecture/issue-178-filesystem-grant-recovery at 7d0325334709dc11a3d8fcb6fbcf59c91e12be30.

The five final clarification/recovery children are merged into this integrated head:

Issues/PRs #300, #301, and #302, plus the earlier stacked remediation children, remain completed as already documented. The final Reviewer verdict is APPROVED for the exact tree, with no blockers or advisories in the inspected scope. This verdict and hosted disposable-service evidence are not proof of correctness or a production deployment.

Final exact-head evidence is green: Web 30564270595 / job 90944729950 (1,754/1,754 units, PostgreSQL 16/16, Redis 3/3, Redis ACL 3/3, combined proof 1/1, S3 16/16, disabled ingress 1/1, build, and E2E 17 passed/59 expected skips); Contract 30564270498 / job 90944730134; GitGuardian green. All 13/13 review threads are resolved; 0 remain outstanding.

Implemented scope and evidence

This stack protects Architect plan history, MCP review history, package and capability evidence, Redis/SSE projections, session-cache writes, clarification projections, recovery and archive paths, root-reference migration proofs, and staged PostgreSQL/Redis/ACL evidence.

Specialist/ACP execution and host-repository writes are disabled by default behind reversible, explicit, auditable controls. Current unavailable paths fail closed where the required confinement boundary is unavailable; the interfaces and capability controls remain extensible for future confined workers and trusted deployment modes.

The exact integrated head has green Web/Contract/GitGuardian evidence for the reviewed stack and combined proof. This body records scoped disposable-service release evidence and does not claim proof of correctness, a production deployment, or arbitrary future sinks.

Closure ledger

Must fix before ready

  • None. All agreed implementation blockers and review conversations are closed. A final live head/check/mergeability sanity recheck is required immediately before changing draft status.

Accepted residual risks

  • Specialist/ACP execution and host-repository writes remain unavailable and fail closed until a separately reviewed confinement and atomic lifecycle boundary exists.
  • Already-started non-cooperative external I/O cannot be transactionally revoked; later Forge mutation boundaries remain fenced after ownership loss.
  • Hosted disposable-service CI is release evidence, not proof of every production/mixed-binary deployment or arbitrary future sink.

Follow-up capability/hardening

  • Confined specialist execution, ACP materialization, and host-write enablement with explicit audited controls.
  • Broader trusted deployment modes, approval models, and future autonomous capabilities.
  • Any new producer or public/durable sink must extend the hostile corpus and combined proof before relying on S4_CROSS_SINK_PRODUCTION_SENTINEL_OK.

Scope freeze

No new adjacent hardening becomes a merge blocker unless it violates an existing acceptance criterion or is a credible high-impact failure in the current supported deployment. Security hardening should enable future capability, not permanently remove it.

Copy link
Copy Markdown
Owner Author

Architecture review update

Completed two orthogonal architecture passes for #179.

Round 1 findings addressed

  • Added fail-closed compatibility for legacy allow_once approvals without a nonce; no synthetic authority is created.
  • Tied agentRunId creation/reservation atomically to the issuance claim to prevent orphan runnable runs.
  • Separated operator grantDecisionNonce from worker lease claimToken.
  • Required semantic parity between SQL partial indexes, Drizzle schema declarations, and conflict predicates.
  • Bounded lease/heartbeat policy using database time.
  • Clarified that packet metadata is staged before every exposure path, including debug/prompt construction.
  • Aligned lock ordering with [FEATURE] S3 — Deterministic bounded filesystem context grant/denial recovery #178.

Architecture updates are in docs/architecture/issue-179-review-amendments.md.

Round 2 result

No further architecture findings identified in the reviewed scope. Implementation must still prove one-winning-claim, stale-token fencing, truthful recovery artifacts, and no deadlock using real PostgreSQL race tests.

This is an architecture-only PR and does not implement #179.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — round 3 findings (before correction)

Verdict: Needs architecture changes. Implementation must not proceed from this revision.

Blocker — packet fencing covers allow_once, not every repository-byte exposure

Blocker — the issuance lease is disconnected from the existing execution lease

  • Architecture: lines 96-167 and amendment lines 19-26 create a second lease/reconciler without a joint state transition.
  • Current implementation: web/worker/work-package-handoff.ts:1986-2060 commits package/run/execution-lease ownership together and has separate heartbeat/recovery paths.
  • Failure: one reconciler can fail an audit while a package/run remains live, or execution recovery can fail a run while issuance continues.
  • Invariant/downstream: no governed read/exposure without both owners; one recoverable terminal state.
  • Smallest correction: execution claim, agent run reservation, issuance audit claim, and one-time consumption share one top-down transaction; one database-time heartbeat renews both; stale recovery fails audit/run, clears the execution lease, writes a distinct issuance marker, moves package to blocked and task to approved, and requires reapproval when a nonce burned.
  • Proof: both lease-expiry orderings, crash points, and concurrent recovery.

High — stale reconciliation reverses the global lock order

Lines 158-167 start with audit rows FOR UPDATE SKIP LOCKED but then need package/run/artifact state. Discover candidate IDs without held locks, then reacquire project → tasks → packages → approval/current decision → agent run → audit and compare-and-set expiry. Test live-owner versus reconciler and grant mutation versus reconciler.

High — audit finalization and artifact uniqueness are not one atomic invariant

Lines 169-190 call both idempotent but allow a crash after terminal audit and before the artifact. Terminal audit transition and partial-index artifact upsert must be one transaction under the token (or a documented durable outbox). Inject the gap and prove exactly one truthful artifact.

High — the packet snapshot persists path-like root

Lines 139-156 contradict the no-path rule at line 156 and ADR 0009. Use an opaque bounded rootRef/project identifier only; legacy absolute roots are never rendered. Bound count maps, stage enums, and sanitized messages. Test a unique absolute-path sentinel across audits, artifacts, task logs, exports, diagnostics, and UI.

Medium — staged and terminal outcomes are conflated

The packetAssembled:false arm includes prompt_submission|finalization, even though assembly already succeeded. Persist an immutable assembly snapshot (assembled or preassembly_failure) before exposure, plus a separate terminal delivery outcome. Never invent zero counts.

Medium — prompt policy and logs need precise boundaries

Only the actual provider system role is immutable; a repeated wrapper after untrusted JSON is a reminder, not a security boundary. Preserve the current prompt-log sanitizer and specify digest/schema/count-only persistence—never prompt, overlay, packet, rejected text, paths, or credentials.

Cross-PR migration requirement

Use additive nullable schema, legacy allow_once without nonce as non-issuable, historical audits as unknown_legacy, dual readers, a worker protocol gate, and a drain before v2 issuance. Rollback leaves additive schema and must not restart a legacy issuer against v2 decisions. Immutable decision attribution must be snapshotted because the approval row is mutable.

Inspected scope: both ADRs, all slice documents, current handoff/executor/lease paths, schema and migration 0020. Confidence: high. This is not proof of correctness; real PostgreSQL and crash-injection proof remain mandatory.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — round 7 findings before correction

The fresh 12-axis pass reverified the prior corrections, then found these remaining S4 blockers:

  1. High / blocking — epoch activation race. “Stable snapshot” is insufficient. Activation must use an explicit PostgreSQL READ COMMITTED transaction: acquire the epoch row exclusively in one statement, then use a second statement/fresh command snapshot to query running null/v1 claims. If v1 obtained the shared lock first, activation aborts; if activation won first, the later v1 transition is rejected.
  2. High / blocking — packet recovery can be bypassed. The current generic handoff selector considers blocked packages and can promote one when canonical admission is allowed. A valid packet_issuance marker must be an absolute pre-admission/promotion guard. Only S4's recovery route or the S3→S4 one-time resolver may clear it and move blocked → ready.
  3. High / blocking — terminal evidence is incomplete. Assembly and delivery alone cannot distinguish success from assembled/not_exposed, accepted-but-invalid/submitted, or other terminal failures. Audit/artifact metadata needs a closed terminal outcome (succeeded or failed with the exact failure code) plus a normative valid-tuple table. Remove arbitrary sanitized failure detail; raw exceptions are not an acceptable packet evidence input.
  4. High / blocking — terminal-audit/live-package split. A crash after terminal audit+artifact commit but before run/package/lease terminalization currently leaves generic recovery delegating to an S4 CAS that only accepts claiming. Add an idempotent S4 repair branch for terminal packet audit + live run/package, or make the whole terminal transition atomic. A CAS miss is “already handled” only after proving run/package terminal and lease cleared.
  5. High / blocking — sibling convergence is unowned. Preserving task running while a sibling lease is live is correct, but current normal aggregation cannot later make the S4-blocked package actionable. S4 needs an explicit post-terminal/periodic top-down task-state reconciler that changes running → approved when the last sibling lease ends without promoting the packet-blocked package.
  6. Medium / blocking — protocol coverage. The epoch trigger applies to every package transition to running, but protocol 2 is stated only for the integrated packet claim. Every v2 transition path, including packet-free execution and no-op handoff, must use one shared claim primitive that sets protocol 2; only packet-bearing paths create an issuance audit.
  7. Medium / blocking — canonical/source and failure precision. readEffectiveGrantState returns source:'project-level' plus grantMode:'always_allow', not project_always_allow; the latter is only the immutable snapshot vocabulary. Also remove terminalization_interrupted unless a durable preterminal intent makes it distinguishable from worker/lease loss.

Required tests include both epoch lock orderings, direct/sibling handoff bypass, every claim mode after epoch 2, terminal-known-audit repair, full valid/invalid evidence tuples, and path-bearing exception leakage. This is architecture correction only; no production implementation is included.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 8 findings (before correction)

Verdict for this round: blocked. The earlier findings are materially resolved, but the fresh orthogonal passes found four remaining contract gaps in S4.

  1. High / blocking — no truthful outcome for valid submitted work that fails later. The current executor can accept a valid provider response, then fail during sandbox apply, validation, host apply, repository-evidence persistence, or completion/review-gate materialization. The closed terminal table permits no accurate code for those paths. provider_response_invalid and worker_stopped would both be false. Host apply may also stop after writing some files, so automatic resubmission is unsafe.
  2. High / blocking — invariant repair can turn immutable success into retryable failure. The repair branch currently preserves any terminal audit/artifact, then fails the live run/package and derives a new worker/lease cause. A terminal-success split must not produce a packet-failure marker, and a terminal-failure split must preserve the exact immutable failure code/delivery rather than invent another cause.
  3. High / blocking — a sibling claim can evade task-disposition serialization. Stale recovery locks only siblings already observed as running/claiming, while packet-free and handoff-only ready → running writers are not yet unambiguously required to lock the task. A concurrent claim can establish a live sibling lease while recovery commits task running → approved.
  4. Medium / advisory — protocol-epoch activation has no assigned operator command/runbook. The three-statement READ COMMITTED protocol is correct, but implementation must provide one checked-in maintenance surface with actor identity, dry-run blockers, idempotency, postconditions, and saved activation evidence. Ad hoc SQL is not an acceptable release procedure.

Required correction: add a closed post-submission failure stage contract and no-auto-resubmit semantics; branch invariant repair by exact terminal outcome; make every all-mode claim and every reconciler contend on task/all siblings in global order; and assign the cutover command/runbook plus executable proofs.

Inspected stack head: 6598f7926c90ed50e2a2b01f0ff5cfeacda87c4c. This is a scoped architecture/current-call-path review, not proof of correctness.

@Joncallim

Copy link
Copy Markdown
Owner Author

Round 8 addendum — additional findings before correction

The final independent state-machine pass found one additional High / blocking issue and two consistency advisories. No correction has been applied yet.

  1. High / blocking — review-gate decisions violate the finalizer lock/freshness contract. The proposed atomic finalizer includes the package/review-gate transition in the top-down transaction, while the current gate-decision path reads gate/package/artifact/run before its transaction, then updates the gate before the package. That can deadlock with the finalizer or let a stale gate decision overwrite a newer running/awaiting-review transition. Add gate rows to the global order after packet artifact/completion inputs, lock project → task → package → relevant gates in stable order, revalidate source run/artifact/package status and lease inside the transaction, and compare-and-set against those identities. Add both-order PostgreSQL races.
  2. Medium / blocking-by-consistency — marker validation needs the complete terminal tuple. The recovery marker alone omits assembly detail. S5 must join the exact prior audit/artifact, prove audit/artifact tuple equality and marker identity, then validate the full assembly/delivery/terminal/failure-stage tuple. It cannot validate compatibility from the marker in isolation.
  3. Medium / blocking-by-consistency — submission_failed cannot be reclassified as lease expiry. The normative tuple permits only submission_rejected for assembled + definitive submission_failed, but the stale-cause priority currently puts lease loss first. Definitive rejection must persist its bounded cause with delivery and recovery must preserve it; add a crash test between delivery staging and terminalization.

The all-mode claim correction will also lock all sibling packages, recompute eligibility under lock, and prove no sibling is running or leased. This preserves Forge's current sequential specialist model, not just task-status consistency.

@Joncallim

Copy link
Copy Markdown
Owner Author

Round 8 addendum — ADR 0008 canonical vocabulary drift

High / blocking: ADR 0008 still says every packet decision audits root, while S4/ADR 0009 prohibit absolute or relative filesystem paths and require a lifetime-stable opaque rootRef. The same paragraph also lacks the corrected separated assembly, delivery, terminal outcome, closed failure stage, and no-content/no-name evidence boundaries. Because the user identified ADR 0008 as canonical packet vocabulary, leaving it stale would give implementers two conflicting sources of truth.

Required correction: make ADR 0008's evidence summary explicitly defer detailed lifecycle/schema to ADR 0009 and state only the privacy-safe vocabulary: opaque rootRef, bounded counts, separated assembly/delivery/terminal state, closed failure code/stage, and no paths/names/excerpts/contents/raw errors. Keep the beta boundary and no-live-handle decision unchanged.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 9 finding (before correction)

Medium / blocking-by-consistency: Round 8 correctly made every recovery reader/action join and validate the exact prior packet artifact, but the route-specific locking prose still stops at the prior runtime audit. The S3 one-time resolver prose has the same omission. An implementation following those numbered locks could validate artifact state outside the transaction even though the normative marker contract says artifact equality is authoritative.

Required correction: lock/read the exact (agentRunId, artifactType='mcp_bounded_context_packet_metadata') artifact after the prior audit in the shared global order; validate canonical typed audit/artifact tuple equality under those locks before an acknowledgement, retry, or one-time resolver mutation. A missing/mismatch remains the typed integrity hold/no-action result.

Inspected final-stack head before restack: 472d896cec1aebbd2fa01c28eb6518bb86f66cc0. Finding posted before correction.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 9 findings (before correction)

Verdict remains blocked on the following fresh post-submission/operability findings.

  1. High / blocking — recovery can race a stale worker's host writes. The contract checks dual ownership before reads, exposure, submission, and finalization, but not after the provider returns or around sandbox apply, validation, per-file host apply, and repository evidence. Recovery could publish an actionable marker while the old process resumes and renames more files. Add a host-process quiescence fence acquired with no database locks, persist post-submission effect intent, keep heartbeats/checks around every stage and per-file atomic replacement, and require recovery to acquire the same fence before terminalizing. If quiescence is unproven, state stays actionless and no new run may start.
  2. Medium / blocking — partial-host evidence has no durable producer. Current code keeps completed files only in memory. Define a run-scoped host-apply ledger with per-entry planned|applying|applied|unknown state, recording intent before and outcome after each atomic replacement under the fence. Reference existing validated output-entry identities; keep paths/raw errors outside packet evidence. Crash after rename/before outcome becomes unknown, and packet retry requires explicit working-tree review recorded against the ledger fingerprint.
  3. Medium / blocking — completion_materialization conflicts with atomic rollback. Rename it completion_preparation and limit it to fallible work before the terminal transaction. Gate insert/finalizer database failure rolls back and leaves the prior durable state; it never persists that stage.
  4. High / blocking — ADR 0008 overclaims both implementation and confinement. It says the S4–S6 beta is implemented and suggests arbitrary host filesystem access is avoided generally. Scope the consequence to the Forge-issued MCP channel, say the architecture takes effect when implemented, and repeat that ACP is not an operating-system sandbox.
  5. Medium / advisory-to-close — integrity holds lack an owner and repair surface. Assign a durable bounded alert, Release/DevOps ownership, a checked-in inspect/repair runbook and command, authorization, fingerprint compare-and-set, and append-only resolution audit. Repair must never rewrite immutable packet evidence or expose retry while evidence/quiescence remains unproven.

Required tests: expiry before/between/after atomic file replacements; crash between rename and ledger outcome; fence acquisition in both orders; pre-transaction completion-preparation versus finalizer rollback; bounded alert deduplication and unauthorized repair rejection.

Inspected stack head: 45506d4de3043e672752d51ffdd9f1f2495bd3e6. Findings posted before correction.

@Joncallim

Copy link
Copy Markdown
Owner Author

Round 9 addendum — sibling review barrier, complete order, and hold authority

Three further blocking-by-contract findings were found before correction:

  1. Forge's current beta runs specialists sequentially through mandatory review. A sibling in awaiting_review has no live lease, so the current “no running/leased sibling” predicate can start the next package or expose a recovery CTA before QA/Review/Security gates finish. The all-sibling package locks must treat awaiting_review as an arbitration barrier; task disposition stays running until no sibling is running/leased/awaiting review.
  2. The order called complete omits multiple artifact rows and append-only issuance-recovery action rows. Define the tail as agent runs ascending → runtime audits ascending → all artifact rows by stable key → recovery-action rows by unique key → review gates ascending. Exact replay/discovery may happen unlocked, but mutation reacquires this order.
  3. The top-level guard currently groups recovery and integrity markers before saying the normal route/resolver can clear “the exact marker.” Split authority explicitly: normal packet recovery/one-time reapproval may clear only packet_issuance; packet_integrity_hold may be cleared only by the separately authorized, fingerprint-bound privileged repair procedure. Every normal action rejects integrity holds.

Required races: claim/recovery versus an awaiting_review sibling and its gate decision; duplicate/replay/one-time resolution versus artifact/action ordering; every normal web recovery action against both integrity-hold reasons.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 10 finding (before correction)

Medium / blocking: the canonical order omits rows newly introduced by Round 9: host-apply ledger/entries and integrity alert/resolution rows. Place them explicitly between runtime audits and review gates. Every per-stage/per-file ledger mutation and every alert/repair mutation uses the applicable prefix/tail; unlocked discovery is allowed, but mutation reacquires the order. A quiescence-timeout alert may be inserted without owning the host fence because it changes no execution state, but it must use a short top-down transaction and never wait for the fence while holding database locks.

Add observed-lock races for per-file ledger updates/finalization/recovery and alert/repair/finalizer paths.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 10 additional blocking finding

Severity: High
Disposition: Blocking for architecture readiness

Host-tree exclusion is not closed over project management routes

The proposed post-submission fence is keyed only by project ID and is shared by worker/recovery. Current project management routes can repoint localPath or recursively delete the repository without acquiring that fence. Because a running worker retains the previously validated root, and because the same canonical host path can later be assigned to another project, project-ID-only exclusion does not prevent overlapping mutation/deletion of the same host tree.

Evidence inspected:

  • docs/architecture/issue-179-context-packet-evidence.md host-fence and stable-rootRef contracts.
  • web/app/api/projects/[id]/route.ts project update and delete filesystem behavior.
  • The restacked Round 10 head and complete lock-order correction.

Required correction before the next review:

  1. Define one canonical host-root resource identity derived from the resolved canonical path, with a project-ID component only as a non-colliding fallback when no host root is configured.
  2. Require worker, recovery, project root repoint, project deletion, and any filesystem-management path to acquire the same resource fence while holding no database locks.
  3. After the fence is acquired, lock/revalidate project/task/package state top-down; reject or wait safely while post-submission effects remain active or quiescence is unproven.
  4. For a root change, fence both old and new canonical root identities in deterministic byte order so path swaps/reuse cannot deadlock or overlap.
  5. Preserve the rule that no code waits for a host fence while holding database locks.

This finding is based on the current implementation's project PUT/DELETE behavior; it is not proof that other filesystem-management paths do not exist.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 10 consolidated addendum

The independent security, QA, and state-machine passes found five additional blocking contract gaps after the top-level order correction.

1. High — Same-root, cross-host, and descendant quiescence are not fenced

  • Fence a stable opaque host-resource identity derived from the canonical physical root, with alias, symlink, and platform case normalization. Pin that identity to the run; do not expose it in packet evidence.
  • Acquire the shared resource fence before the first repository-context read or packet assembly and retain it through provider submission, all local effects, terminal finalization, and descendant quiescence. A post-submission-only fence cannot prevent a root repoint from turning the old path into another project's repository while the first run still reads or writes it.
  • Project root repoint must fence old and new resource identities in deterministic byte order. Project delete and every host-filesystem management path must acquire the same fence with zero database locks.
  • Root mutation/reuse also increments a persisted project root-binding revision. Claim pins the canonical resource identity and revision; every repository read/effect/finalizer revalidates the pin. Repoint/delete/reuse cannot commit while any pinned claim remains active or quiescence is unproven.
  • Recovery must prove an authoritative currentHostId === effectIntent.hostId before local fence acquisition or terminal mutation. A mismatch or unreachable owning host is alert-only.
  • A dedicated supervisor/process-group protocol must retain the fence through every descendant. On worker/control-channel death it terminates and waits for the process group; the inherited fence remains held until the last descendant exits. Hosts that cannot prove this capability fail closed for protocol-v2 local effects.

2. High — S3/S4 review aggregation is contradictory

The S4 resolver called from S3 must participate in the task-wide awaiting_review barrier. It locks sibling packages in canonical order even though grant evaluation remains package-local. No recovery action or running → approved transition may occur while a sibling review is unresolved.

3. Medium — Individual mutating paths still omit the complete tail

The acknowledgement/retry route, one-time resolver, invariant repair, success repair, integrity resolution, and gate decision must each explicitly acquire applicable rows in the canonical suffix: host ledger/entries → all artifacts → recovery actions → integrity alerts/resolutions → review gates. The route cannot validate host-review or integrity state from unlocked rows.

4. Medium — Activation cannot prove host capability/routing

The planned activation command promises to report every worker/fence/same-host blocker, but no durable capability evidence exists. Keep the initial v2 local-effect rollout explicitly single-active-host. Add a durable worker-host capability registration/heartbeat with stable opaque host ID, supported protocol version, fence-supervisor capability, last-seen time, and drain state. Activation fails unless exactly one fresh active host is registered and every legacy/incompatible worker is drained; its audit snapshots the registrations. Multi-host local effects remain disabled until a later host-affine routing design.

5. Medium — Terminal/effect/ledger and mismatch outcomes are underspecified

  • Add one exhaustive compatibility table for assembly, delivery, terminal result/code/stage, effect intent, host ledger, and host review. Terminal post-effect rows require quiesced; active is nonterminal only; caught local failure requires lastStage === failureStage; success forbids planned|applying|unknown; submitted-before-effect failures use not_started. SQL checks, parsers, finalizers, recovery, S5, and S6 consume the same table.
  • A true immutable audit/artifact mismatch may satisfy neither verified success nor coherent failure. Define an evidence-preserving append-only quarantined_abandoned adjudication that terminally closes the task/package without making the packet retryable or rewriting either record. The operator copy must say permanent evidence quarantine/closure, not repair.

These are architecture gaps, not claims that the future implementation or host behavior has been proven.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 11 findings

Disposition: Changes requested before architecture readiness

Medium — Wrong-host predicate references a field absent from not_started

Recovery currently requires the authoritative current host ID to equal both the run pin and effectIntent.hostId. The not_started union arm intentionally has no host field, including the documented submitted-before-effect crash. That path cannot implement the stated predicate.

Required correction: always compare current host with the locked work-package/agent-run host pin; compare effectIntent.hostId only for active|quiesced. Add wrong-host tests for both not_started and active effects.

High — A caught live host-write failure can still be outcome-ambiguous

The compatibility table says a caught live local failure cannot contain ledger unknown. But an atomic replacement can succeed and the following applying → applied database write can fail or lose ownership. The still-live worker cannot truthfully infer whether the durable filesystem effect and database outcome agree merely because it caught the error.

Required correction: while retaining the resource fence, any live path that cannot durably prove applied maps the entry to unknown before terminalization, or leaves the run nonterminal for recovery if PostgreSQL is unavailable. A caught host_apply failure may therefore contain unknown, must set fingerprint-bound review_required, and cannot expose a new run until review. Success continues to forbid unknown.

These findings are new Round 11 checks; the broader resource-fence/root-binding correction remains intact.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 11 consolidated lifecycle findings

Disposition: Changes requested; all findings block architecture readiness

1. High — Hard project deletion destroys immutable evidence

Current foreign keys cascade project deletion through tasks, packages, runs, and artifacts. The proposed root cleanup still ends by deleting the project, contradicting permanent packet evidence, integrity alerts, and quarantine resolution retention.

Required correction: protocol-v2 projects use a soft-delete tombstone. Final deletion clears the path and releases the live root binding but retains project/task/package/run/audit/artifact/action/alert/resolution rows. The unique root constraint applies only to non-deleted projects. Normal queries hide tombstones; hard purge is forbidden until a separate retention/export architecture exists.

2. High — A nonexistent clone destination has no physical identity to fence

GitHub/local creation can clone or create a directory before a project row or physical root exists. Two requests can pass pathExists; a losing clone can then remove the winning destination. A physical device/object-derived hostResourceRef cannot be acquired before creation.

Required correction: add a typed pre-create reservation keyed by authoritative host + canonical existing parent identity + platform-normalized missing suffix. Acquire its namespace fence before mkdir/clone, persist planned|materialized|bound|cleanup_required, and retain it while deriving/acquiring the new physical resource fence and atomically inserting the project binding. Crash/loser cleanup must compare reservation token and object identity and must never delete a later reused path.

3. High — Worker registration is checked only at activation

An epoch-2 claimant can currently supply protocol/host/supervisor settings without proving a fresh active forge_worker_instances row. Add transaction-local instance ID, pin it on package/run, and have the running-transition trigger lock the exact instance row after the epoch row and verify active/fresh/host/protocol/supervisor/binding-key equality. Activation/drain lock epoch then instance rows. Add worker-instance rows to the canonical database order after the epoch.

4. High — Inherited file descriptors do not prove ACP descendant quiescence

A child can close extra descriptors or daemonize, and supervisor-first death can release the lock while the main worker continues. Replace the inherited-descriptor claim with a host fence service plus an OS-enforced containment adapter that includes the Forge worker, ACP transport, validation children, and every descendant. The service owns the resource lock and durable local lease; worker/service/control loss makes it orphaned and actionless. Automated release requires the containment adapter to prove the group empty. Unsupported or unverifiable hosts fail closed for protocol-v2 local-root execution; no process-memory/process-tree guess is accepted.

5. High — Binding-key and old root writers are not fenced by cutover

Every worker/epoch/root binding must carry one stable host-binding-key fingerprint; divergent key material on the same host blocks activation/claim. Define backup and rotation as drain → disable → rebind, never silent key replacement.

Add an expand-phase project-root mutation trigger serialized with the epoch. At epoch 1, legacy create/repoint clears/invalidate nullable bindings and forces explicit rebind; at epoch 2 it rejects missing/malformed host ID, resource ref, revision, maintenance token, or authorized writer settings. Activation's fresh snapshot plus exclusive epoch lock then durably excludes stale web/root-management writers, not only workers.

These corrections must preserve the rule that no database lock is held while waiting for a namespace/resource/containment fence.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 11 evidence-bypass finding

Severity: High
Disposition: Blocking

Unconfined ACP work can bypass the host-review gate

The architecture correctly says prompt text cannot stop an Agent Communication Protocol (ACP) runtime from making equivalent shell or filesystem changes. However, the normative table treats submission_uncertain or submitted-before-local-stage as effectIntent:not_started, no host ledger, and hostApplyReview:not_applicable. A provider can change the repository during submission, crash before Forge's local stage, and leave no Forge ledger. The resource fence proves later quiescence, but it does not prove that the repository remained unchanged.

Required correction: capture a repository baseline before ACP submission and a post-quiescence change fingerprint under the same resource fence. Detected or unverifiable external-runtime changes require fingerprint-bound working-tree review before acknowledgement, retry, reapproval, root management, or a new run. Apply this rule to provider success as well as failure. If that evidence cannot be produced, protocol-v2 packet guarantees must exclude unconfined ACP execution.

Privileged quarantine can bypass a sibling's mandatory host review

quarantined_abandoned cancels nonterminal siblings and closes the task after effect quiescence, but it does not require every affected sibling's host-apply review to be complete or bind those ledger fingerprints. Root management currently blocks unresolved markers only on nonterminal tasks. A sibling with an unknown host entry can therefore lose its root-management barrier when another sibling is quarantined.

Required correction: permanent quarantine must either bind and acknowledge every affected sibling's exact repository-change and host-ledger fingerprints, or append a separate privileged repository-abandonment acknowledgement. An unresolved review/marker remains a project-root management barrier even after task terminalization until that explicit evidence-bound action exists. Normal quarantine must never turn unknown physical work into permission to repoint, delete, or reuse the root.

These are evidence-state findings. They do not assert that a future containment or fingerprint implementation is correct.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 12 findings (before correction)

High — Terminal success still permits unresolved external repository changes

The new lifecycle correctly says a changed or unverifiable post-ACP repository comparison stops all Forge local stages and terminalizes with external_repository_change_requires_review. The normative compatibility table still permits a successful row whose repository review is review_required|reviewed.

That tuple is contradictory and actionless: success creates no recovery marker, so an unreviewed successful row has no valid acknowledgement path; a later review also cannot retroactively turn the stopped failed run into an original success.

Required correction: terminal success requires baseline comparison unchanged and repository review not_applicable. Every changed or unverifiable result after ACP is terminal failed with the external-change code (or would need a separate explicitly designed nonterminal human-review state, which is not introduced here). The shared PostgreSQL/finalizer/repair/parser/API/S5 table must reject every success + changed/unverifiable/review-required/reviewed cross-product.

Low — The tombstone duplicates Forge's existing project lifecycle field

The proposal adds projects.deleted_at, but the current schema already has projects.archived_at, and normal project/task queries already use it as the non-live project boundary. Two nullable hiding fields would create ambiguous uniqueness, query, and authorization predicates.

Required correction: use existing archived_at as the protocol-v2 deletion tombstone, add only the missing bounded actor/reason audit field if needed, and define the live-root partial unique index and all normal/evidence queries against that one field. “Archive” for this slice means the root/path is released while immutable evidence remains; hard purge remains forbidden.

Both findings are architecture-contract issues, not implementation findings.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 12 additional findings (before correction)

High — Binding-key rotation is circular under the epoch and root triggers

The current sequence installs K2, recomputes/rebinds every root, then reactivates. Epoch-2 root mutation accepts only the exact active epoch/instance key, while activation requires every live project already to be bound to that active key. Starting from epoch K1/projects K1, a K2 writer cannot rebind. Promoting the epoch to K2 first also fails activation because the projects still carry K1.

Required correction: define a privileged two-phase rotation state with active K1, pending K2, and a one-time rotation token/credential. Enter it only after ingress is disabled and the old worker/root-writer fleet is drained with no active leases or root reservations. Only the rotation command may fence both old and pending references and batch compare-and-set live projects/reservations. Verify the complete K2 set, then atomically promote K2 and rotate ingress credentials. Specify crash resume versus rollback, including whether root-binding revisions and prior decisions rotate or remain immutable. S6 must inject failure at every batch and promotion boundary.

High — Pre-create reservations bypass the exact root-writer instance contract

Reservation rows carry host/key/token/state data but no exact root-writer instance or credential-generation pin. The root-mutation trigger covers project rows, not reservation planning/materialization/cleanup. The stated transaction order locks only the reservation row, so it cannot prove the epoch and exact fresh writer instance that authorizes mkdir, clone, cleanup, or final bind.

Required correction: pin each reservation transition to the exact root-writer instance and credential generation. After acquiring the namespace fence with zero database locks, every reservation planning/materialization/cleanup/bind transaction must lock in the canonical order protocol epoch -> exact root-writer instance -> reservation, revalidate freshness/drain/key/credential/host state, and fail closed on divergence. S6 must cover stale, draining, unregistered, wrong-key, and wrong-generation writers both after planning and after filesystem creation, plus activation/drain races.

These are architecture-contract findings, not implementation findings.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 12 state-machine finding (before correction)

High — Successful runs have two contradictory effect-intent tuples

The normative compatibility table permits succeeded + not_started + no ledger in the “valid response persisted, before first Forge local stage” row. Its final “successful run” row simultaneously requires every success to use quiesced(lastStage), including when there was no host-write plan. quiesced requires a real bounded lastStage, so a run with no Forge local effect cannot satisfy that second row without inventing a stage.

Required correction: split success into two disjoint exhaustive tuples. A successful run with no response-driven local stage remains not_started, has no host ledger/review, and requires unchanged repository evidence. A successful run that began local work is quiesced(actualLastStage); any declared host-write plan has a complete applied ledger, and host review remains not_applicable. Remove succeeded from the generic pre-stage row so success is admitted only by these explicit success rows. The shared PostgreSQL/finalizer/repair/parser/API/S5 predicate must reject every overlap or invented-stage variant.

This is an architecture-contract finding, not an implementation finding.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 12 additional findings (before correction)

High — Same-host recovery has no authenticated current worker identity

The durable pins name the historical claiming worker instance, and stale recovery locks only that exact row. The same section says a missing or stale registration is alert-only. After worker W1 crashes and its row becomes stale, a fresh same-host worker W2 is therefore neither named, locked, freshness-validated, nor recorded: requiring W1 freshness makes recovery impossible, while allowing W2 without a durable pin makes it unauthenticated.

Required correction: retain W1 as immutable claim history and add an exact recovery_worker_instance_id (or equivalent recovery-attempt row) for the current recovery owner. After the epoch, lock historical and current instance rows in ascending ID order; require W2 to be fresh, active, same authoritative host/key/protocol/containment generation, and distinct from any stale-ID takeover. Persist W2 identity/token/lease before host-fence recovery. S6 must prove W1 crash -> valid W2 same-host recovery, stale/wrong W2 rejection, and no reuse of W1's stable ID.

Medium — Repository-change abandonment has two incompatible state models

RepositoryChangeReview includes abandoned, and the general barrier permits review or abandonment. The normative tuple table and S5 presenter accept only not_applicable|review_required|reviewed, while integrity quarantine separately stores a repository disposition of reviewed|abandoned. SQL, parser, recovery, and UI therefore cannot share one closed union.

Required correction: keep abandoned exclusively as an integrity-quarantine resolution disposition, not a normal repository-change review state. Normal review remains not_applicable|review_required|reviewed; quarantine binds the original review fingerprint plus the separate reviewed/abandoned resolution disposition. Align every table/type/parser/presenter reference.

Low — The repository-review barrier blocks its own acknowledgement

The lifecycle says an acknowledgement cannot proceed until repository review is already reviewed/abandoned, while the recovery-action section says that same exact acknowledgement changes review_required to reviewed.

Required correction: all later authority, retry, reapproval, root management, and unrelated actions remain blocked, but the one fingerprint-bound acknowledgement that atomically completes the review is the explicit exception.

These are architecture-contract findings, not implementation findings.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 12 containment finding (before correction)

High — The normal containment lifecycle cannot become empty

The current contract places the Forge worker itself plus ACP, validation, and response-driven descendants in one non-escapable lease group, then requires a normal owner to wait until that complete group is empty before releasing the resource fence. Forge's worker is a long-lived queue loop. While that durable worker remains a member, the group cannot become empty, so a successful run cannot release its fence without terminating the queue worker.

Required correction: keep the durable queue/control worker outside the containment group. It asks the trusted fence service to create a per-run execution child; that child and every ACP/validation/local-effect descendant enter the non-escapable run group before repository access. Specify the authenticated handoff, owner token, normal child exit/group-empty proof, durable lease release, and crash/orphan takeover protocol. The queue worker may observe/control the run but is not evidence of group emptiness.

This is an architecture-contract finding, not an implementation finding.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 12 sibling-claim finding (before correction)

High — Unresolved local-change review is not enforced at the all-mode claim boundary

The lifecycle says a changed/unverifiable repository or uncertain host write blocks every later run. The shared all-mode sibling claim currently rejects only running|awaiting_review siblings and live execution leases; task reconciliation uses the same narrow test. A terminal sibling can therefore retain hostApplyReview or repositoryChangeReview:review_required while another ready packet, packet-free, or handoff package claims and reads/mutates the same repository.

Required correction: materialize one task/project unresolved-local-change barrier derived from the exact sibling host/repository review fingerprints, or make every all-mode claim lock and validate all sibling audits/ledgers/reviews in canonical order. Task status must not become claimable while any exact review is unresolved. Acknowledgement/quarantine clears only the matching fingerprint-bound barrier; it never rewrites immutable evidence.

This is an architecture-contract finding, not an implementation finding.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 12 root-exclusion finding (before correction)

High — Exact root identities do not exclude ancestor/descendant repositories

Live-root uniqueness and missing-root reservation keys reject only equal physical roots. /workspace/foo and /workspace/foo/bar have different resource/reservation keys and can materialize concurrently. A parent clone or recursive cleanup can then overwrite/delete a nested project's root even while that nested binding and object identity remain valid. This also regresses Forge's current intent to reject overlapping project paths.

Required correction: define a prefix-aware hierarchical namespace reservation/fence protocol and a durable no-ancestor/no-descendant constraint for every live root and reservation on one host. Acquisition uses a canonical hierarchy order without database-lock/fence inversion. Create, repoint, cleanup, tombstone, and reuse prove that no conflicting ancestor or descendant binding/reservation exists; recursive cleanup additionally proves the protected subtree contains none.

This is an architecture-contract finding, not an implementation finding.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 12 evidence-scanner finding (before correction)

Medium — Repository comparison has no bounded hostile-filesystem contract

The design requires a complete content/metadata baseline but does not define lstat behavior, symlink and special-file handling, exclusions, stability, or count/byte/time ceilings. A FIFO, device, socket, loop, concurrent churn, very large file, or enormous untracked tree can hang or exhaust a worker instead of reaching bounded preflight failure or post-call unverifiable evidence.

Required correction: define a versioned bounded scanner. It never follows symlinks, reads content only from regular files, records bounded metadata for links/special entries, excludes .git internals and Forge's own protected runtime state by an exact versioned rule, and enforces file/count/byte/time ceilings. A double-scan or equivalent proves a stable snapshot. Pre-submission overflow/instability fails before ACP exposure; post-submission overflow/instability produces unverifiable and the external-change review barrier.

This is an architecture-contract finding, not an implementation finding.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 12 mixed-version finding (before correction)

Medium — The epoch-1 root trigger cannot invoke S3's sole TypeScript reconciler

The proposed database trigger cannot call the TypeScript S3 reconciler, and locking task/package/approval rows after it has acquired project -> epoch reverses the documented order.

Required correction: make the rollout executable. Prefer no live old-web/root-writer window with the root trigger: disable project ingress, revoke and terminate v1 database access, drain old services, run S3 reconciliation/root backfill under the canonical application lock order, then enable the root trigger and epoch 2 before v2 ingress. The trigger validates protocol-v2 root mutation only and never reimplements S3. If a mixed writer bridge is chosen, the application must reconcile before project mutation and the trigger validates an exact proof without acquiring downstream rows.

This is an architecture-contract finding, not an implementation finding.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 12 recovery-action finding (before correction)

High — submission_failed plus repository change has no action that can complete review

The compatibility table permits a definitively rejected submission_failed attempt whose post-call comparison is changed|unverifiable and review is required. The recovery disposition jumps directly to reapprove_allow_once or retry_execution; acknowledgement/review is exposed only for uncertain/submitted delivery. Retry/reapproval then requires review already complete, leaving this valid tuple permanently actionless.

Required correction: make exact host/repository review a delivery-independent prerequisite state. Any marker with a required review first exposes only a typed fingerprint-bound review_local_changes acknowledgement (or privileged quarantine). After it atomically completes all required reviews, derive the delivery/grant-mode action: definitive rejection -> reapprove/retry; uncertain/submitted -> acknowledge prior exposure semantics plus reapprove/retry as applicable. No action changes immutable delivery.

This is an architecture-contract finding, not an implementation finding.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 12 fence-service trust finding (before correction)

High — The fence service is not protected from the explicitly unconfined ACP runtime

The host fence service owns the only durable lease/release authority, while ACP retains shell, network, credential, and filesystem access. The contract does not give the service a separate operating-system principal, protected state/socket, peer authentication, or a run-bound lease capability. An ACP process with the worker's host authority could call or tamper with the service, replay another run's release, delete state, or combine state damage with service termination.

Required correction: run the service under a protected principal with a protected state directory and socket/API. Validate kernel peer credentials and an unguessable capability bound to run, current worker instance, root identity, and containment group. Independently prove kernel group emptiness on every release; never trust a caller's declaration. Tamper, corruption, replay, service death, or unverifiable peer/group state becomes durable orphaned/disabled state and blocks root reuse.

This is an architecture-contract finding, not an implementation finding.

@Joncallim

Copy link
Copy Markdown
Owner Author

Integrated architecture review — Round 12 tombstone-state finding (before correction)

High — Tombstoning retains nonterminal work that can execute after project removal

The tombstone retains tasks/packages but does not close ordinary pending|ready|approved|blocked work. The shared all-mode claim rejects root maintenance and selected sibling states, but does not reject a tombstoned/archived project. Queue replay or periodic progression can therefore run packet-free or rootless work for a project already hidden as removed.

Required correction: the tombstone transaction atomically closes/cancels every nonterminal task and package with one bounded project-removed audit reason, while retaining all immutable history/evidence. Queue discovery, direct progression, sibling reconciliation, and every all-mode claim also reject archived_at IS NOT NULL as defense in depth. No tombstone transition is allowed while a live execution/review/local-change barrier prevents safe cancellation; quarantine remains evidence, not executable work.

This is an architecture-contract finding, not an implementation finding.

docs: document combined cross-sink production proof
…ion-proof

test: prove production cross-sink sentinel closure
@Joncallim
Joncallim marked this pull request as ready for review July 30, 2026 01:58

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 90763b2714

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread web/worker/orchestrator.ts Outdated
Comment thread web/scripts/bootstrap-epic-172-s4-roles.ts
@Joncallim
Joncallim marked this pull request as draft July 30, 2026 05:08
@Joncallim
Joncallim marked this pull request as ready for review July 30, 2026 15:15

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 90763b2714

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread web/app/api/tasks/[id]/questions/route.ts Outdated
Comment thread web/lib/task-event-redis.ts Outdated
Comment thread web/worker/queue.ts Outdated
Comment thread web/app/api/tasks/[id]/questions/route.ts Outdated
@Joncallim
Joncallim marked this pull request as draft July 30, 2026 15:47
@Joncallim
Joncallim marked this pull request as ready for review July 30, 2026 17:15
@Joncallim
Joncallim merged commit 06a1442 into architecture/issue-178-filesystem-grant-recovery Jul 30, 2026
5 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b1c99d6cd5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// supplied runtime environment. The request flags are intentionally unable
// to open this boundary until an OS-enforced confined writer exists.
void env
return false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Restore specialist execution behind the runtime flag

For every approved package, this now returns false regardless of FORGE_WORK_PACKAGE_EXECUTION, so the branch at handoffApprovedWorkPackages can never call executeReadyWorkPackage; Forge records a no-op handoff and may complete the task without running a specialist or applying its files. This removes the repository's default execution path and also makes an explicit FORGE_WORK_PACKAGE_EXECUTION=1 ineffective; preserve the existing flag semantics rather than hard-disabling the path.

AGENTS.md reference: AGENTS.md:L30-L35

Useful? React with 👍 / 👎.

const response = await fetch(`/api/tasks/${taskId}/architect-plan-history/${planVersion}`)
if (!response.ok) throw new Error('Protected clarification history is unavailable')
const body = await response.json() as { entries?: Array<{ entryId: string; entryKind: string; content: string }> }
setClarificationQuestions(clarificationQuestionsFromHistory(body.entries ?? [], summaries))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Hydrate the approval UI from Architect history

For protected plans, this is the only browser request that receives the authorized Architect entries, but it retains only clarification entries. The Implementation Plan and MCP review panel still read the generic artifact projection, whose Architect content is the fixed placeholder and whose metadata omits mcpExecutionDesign; operators therefore cannot inspect the generated plan, and a plan with MCP requirements cannot render or save its mandatory review even though the approval API rejects approval without it. Store and project the plan body and MCP requirement entries returned here into those views.

AGENTS.md reference: AGENTS.md:L30-L33

Useful? React with 👍 / 👎.

Comment on lines +7296 to +7298
v_next_marker := NULL;
IF p_action = 'acknowledge_possible_submission' THEN
v_next_marker := v_marker || pg_catalog.jsonb_

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Requeue tasks whose legacy questions are invalidated

On an upgrade with a task already in awaiting_answers, this changes every pre-S4 question to legacy_unavailable without changing or requeueing the task. The questions API accepts only protected rows whose status is open, while ordinary task retry rejects awaiting_answers, leaving the page requesting answers that cannot be displayed or submitted; the operator's only workaround is to stop and restart the task. Transition affected tasks to a recoverable state during migration or preserve a usable protected clarification source.

AGENTS.md reference: AGENTS.md:L30-L33

Useful? React with 👍 / 👎.

Comment on lines +96 to +100
SET provider_type_used = provider.provider_type,
provider_is_local_used = provider.is_local,
provider_config_updated_at_used = provider.updated_at,
acp_execution_mode = CASE WHEN provider.provider_type = 'acp'
THEN 'unconfined_host_process' ELSE 'not_applicable' END

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid fabricating provider snapshots for old runs

When a provider configuration has been edited since an old run, this backfill records the configuration's current type, locality, update time, and derived ACP mode as values used by that historical run. Because the provider API permits changing both providerType and isLocal, an old cloud run can consequently be exposed as a local ACP unconfined-host run, or vice versa, corrupting the new execution evidence. Preserve an explicit unknown legacy state or populate these fields only from genuine run-time history.

Useful? React with 👍 / 👎.

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