feat(server): forge state-transition arms and actor memo (RIG-3331) - #1018
Draft
rigel-mintaka wants to merge 1 commit into
Draft
feat(server): forge state-transition arms and actor memo (RIG-3331)#1018rigel-mintaka wants to merge 1 commit into
rigel-mintaka wants to merge 1 commit into
Conversation
This was referenced Sep 8, 2026
|
Compass engineering docs preview: https://compass-forge-rig-3331-serve.compass-eng-docs.pages.dev Deployed from |
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.
Implements T4 of
docs/designs/server/compass-forge-state-transition/design.md— the server arms and the actor memo. Stacked on #1017.The arms
Two
forgeServicearms following the existing shape:resolveTarget, arm validation, author-client dispatch,mapForgeErrorflattening, updated canonical artifact through the existingtranslateIssue/translatePR.Three validation screens, all before any provider touch:
openorclosed; anything else (includingmergedand a Linear workflow-state name) isinvalid_argument.close_reasonis GitHub-issues-only,workflow_stateis Linear-only. Rejected HERE, keyed on the RESOLVED coordinate, which is why a provider may safely ignore a foreign refinement.No F3 dedup and no owner stamp on either arm:
client_request_idis documented "ignored on non-create arms", and a transition has no body to stamp.The memo (why it exists)
A transition has no body, so the owner header cannot attribute it, and every Server-credential write presents the shared App bot login. Durable server-side correlation is the only channel that can name WHICH agent drove a transition — that is what RIG-3331 OQ-1 ruled (2026-09-07), and it is what RIG-3326's STATE arm consumes.
forge_state_transitionslands in0001_init.sql, not a new numbered migration: that directory holds exactly one migration by a standing ruling, and the same reasoning folds each later migration in as it accretes. It is coordinate-aligned toforge_authored_artifacts— same(tenant_id, forge_provider, forge_host, repo, kind, number)PK — so a re-transition re-lands on the key rather than accreting rows.Load-bearing properties:
tenant_idis not incidental. Two tenants legitimately hold the same forge coordinate, so without it one tenant's memo could attribute another's STATE event. It rides the column DEFAULT + RLS, never a caller argument, matching theAuthoredArtifactByCoordinateprecedent.UPDATE … RETURNING), so claim and read are atomic and a concurrent second reader matches nothing.forge_authored_artifactsrow — that row is write-once authorship whose DO UPDATE would destroy the original create's idempotency memo. Asserted explicitly.merged, outside both the notify lane's match domain and the table's CHECK.One judgment call the record did not spell out
The upsert resets
consumed_atto NULL. Without it, an agent that closes an issue (memo consumed) and later reopens it is permanently unattributable at that coordinate, contradicting "latest transition wins". It is behind its own named test so it can be reversed in one place.Tests
13 unit tests in
go/serverover fake provider + fake store: dispatch on both arms, every validation rejection, memo written only after success, memo absent after failure, PR memo carries the portable state and PR kind. Includes a positive control — a screen that rejected EVERY refinement would pass the two rejection tests alone.7 store pgtests, executed against real Postgres: upsert-latest-wins, upsert re-arms a consumed memo, consume-exactly-once, freshness bound (and its inclusivity), and one miss case per coordinate component.
The RLS coverage was proven load-bearing, not just written: removing the
forge_state_transitionsentry from the DO-loop turnsTestRLSCatalogEnabledAndForcedRED.Ledger-impact: none — DL-342/DL-343 landed with the record's freeze in #981.