feat(agent-ledger): assign update for allow-list extension#24
Merged
Conversation
albertgwo
commented
May 12, 2026
albertgwo
commented
May 12, 2026
albertgwo
commented
May 12, 2026
albertgwo
commented
May 12, 2026
albertgwo
commented
May 12, 2026
albertgwo
commented
May 12, 2026
albertgwo
commented
May 12, 2026
albertgwo
commented
May 12, 2026
… docs Address PR #24 review findings: - Reject blank or whitespace-only --add-allow values at the CLI boundary and add a domain-level ErrEmptyAddAllowedPaths guard so a direct caller cannot get a Reused=true no-op from an empty addition set. - Drop the metadata.updated_from key. The chain is already represented by superseded_by and superseded_assignment_id; the second key had no consumer and no documented meaning. - Include --orchestrator overrides and non-reserved --metadata keys in idempotent change detection so those inputs no longer drop silently on a request whose --add-allow values are all already present. - Reword --agent help text: omitting or passing empty intentionally targets the unassigned assignment chain. The prior 'required' claim contradicted the actual behavior. - Rename the external stale-update test to describe what it really covers (rotation after an out-of-band supersede). Add an internal test that exercises supersedeAssignmentTx's zero-row branch directly, so the ErrStaleUpdate sentinel has real coverage. - Fail loudly on Scan errors in the idempotent-path event-count queries and on the second json.Unmarshal in the CLI happy-path test so a silent schema or decode failure cannot mask a regression. - Add SPEC entries for the new invalid_flag/invalid_metadata exit codes, the dropped reserved key, and the broader idempotency contract.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Purpose
Close the kernel gap where an active assignment's allow-list was fixed for the lifetime of the task. Operators that wanted to extend an in-flight assignment had to choose between living with
warnpolicy drift, editing SQLite by hand, or rotating to a newtask_idand breaking the worker'sAGENT_LEDGER_TASK_IDenv.Summary of changes
agent-ledger assign update --task <id> --agent <agent-id> --add-allow <glob>... --reason "<why>"subcommand under the existingassignparent. Allow-list extension only; idempotent (rerunning the same flags returnschanged=false reused=true).domain.SupersedeAndInsertAssignmentdoes lookup, merge, supersede, and insert in oneBEGIN IMMEDIATEtransaction. Generates ids and timestamp inside the callback so a writer that loses the lock race cannot commit timestamps that pre-date the winner. Strips reserved lineage keys (superseded_by,superseded_assignment_id,updated_from) from caller-supplied--metadataso callers cannot inject false lineage onto the new active row.assignment.superseded(replacement event, not closure). The new active row also emitstask.assignedwithmetadata.superseded_assignment_idpointing back at the prior row.assignment_idis one immutable scope-contract instance; the human concept is a chain linked via the lineage metadata keys). §12.1 addsassignment.superseded. §18.3.1 documents theupdatesurface, atomicity, idempotency, and exit codes.Changes to review
internal/domain/domain.go: confirm theWriteDomainEventImmediatecallback inSupersedeAndInsertAssignmentis the only writer that touches the row (no out-of-callback mutations) and thatisReservedLineageKeycovers every key the helper sets later.internal/commands/assign_update.go: confirmErrStaleUpdateandErrAssignmentExistscollapse to one user-facingassignment_stale_updatecode with identical retry guidance.SPEC.md§11.3.1, §12.1, §18.3.1: confirm the identity rule and event-type promotion match the implementation, and that the documented exit-code list (missing_flag,reason_unsafe,no_active_assignment,assignment_stale_update) is complete.--add-forbid,--remove-*, full-replacement,--policychange, and standaloneassignment.closedare intentionally deferred. Adding a forbid glob that overlaps an already-claimed path narrows what an in-flight intent may write, andrecordvalidates against intent path hashes (not current assignment scope), so the failure surfaces only at verify time. The deferral is named explicitly in SPEC, walkthrough, and CHANGELOG.