feat(fiber): transitionPolicy dial + auto-declared machines deps#194
Open
ottobot-ai wants to merge 1 commit into
Open
feat(fiber): transitionPolicy dial + auto-declared machines deps#194ottobot-ai wants to merge 1 commit into
ottobot-ai wants to merge 1 commit into
Conversation
Implements Proposal 03 F6 + F7 (additive, default-preserving). F7 (combiner enforcement + opt-in dial): - New `TransitionPolicy` ADT (Open < OwnersOrParticipants < Owners) in schema/fiber, modeled on UpgradePolicy's bare-string codec (total, fail-closed). Added as `Constrained.transitionPolicy: Option = None`, omit-safe, joined to the `tightens` lattice as a rankUp dial. - Signer-authorization is now enforced in `FiberCombiner.processFiberEvent` (the authoritative apply path) as a graceful `CombineRejected`, before `orchestrator.process` — reads ONLY the fiber's own hash-pinned policy dial + the stable owners/authorizedSigners record fields (rule #2/#3 safe). - ABSENT dial defaults to `Open` (today's live guard-only behaviour) so every existing fiber is UNCHANGED; apps opt UP explicitly. The default-tightening flip (§3.4/§6 Q1) is deliberately left to the maintainers. F6 (auto-declare static machines.<uuid> read deps): - `StaticDependencyScan.staticMachineRefs` walks a transition's guard/effect AST for literal `{"var":"machines.<uuid>..."}` paths and augments the RUNTIME dependency set handed to `ContextProvider.buildContext`. Never mutates the signed, hash-pinned `Transition.dependencies` (rule #1). Tests: TransitionPolicyEnforcementSuite (default-Open applies, Owners rejects non-owner, OwnersOrParticipants accepts participant/rejects stranger), AutoDependencyScanSuite (pure scanner + end-to-end resolution), PublishVersionSigningCanonicalSuite (+2 cases: absent dial byte-identical, set dial round-trips). TransitionOwnerGateDivergenceSuite and MultiPartyTransitionSigningSuite stay green. Full sharedData: 576/0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R5TUSJPD8FCtJagf7siXgt
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 F6 + F7 of the fiber-ergonomics program (
docs/proposals/fiber-ergonomics/03-cross-fiber-and-authorization.md). Stacked on #192 (the RFCs + theTransitionOwnerGateDivergenceSuiteregression test this PR's fix flips green); retargets tomainwhen #192 merges.F7 — close the transition-authorization enforcement gap (the security fix)
Today the transition owner-gate is coded in
validateSignedUpdatebut not in the combiner, so the authoritative apply path advances committed state for any signer whose transition passes the guard (pinned byTransitionOwnerGateDivergenceSuitein #192). This PR makes signer-authorization actually bind, and makes the posture explicit:TransitionPolicyADT (Openrank 0 /OwnersOrParticipantsrank 1 /Ownersrank 2) +FiberPolicy.Constrained.transitionPolicy: Option = None.Option/omit-safe, bare-string codec, collapses throughisEmpty/constrainedlike every other dial, and joins the tighten-only lattice as arankUpdial (a migration may only goOpen → OwnersOrParticipants → Owners, never launder back down).FiberCombiner.processFiberEvent, after the sequence check, beforeorchestrator.process) as a gracefulCombineRejected— the authoritative-gate pattern registry/asset ops already use. Resolves verified signer addresses fromupdate.proofs(mirrors the create path +updateSignedByOwnerOrParticipant).Open(deliberate, additive)An absent
transitionPolicyresolves toOpen= today's live guard-only behavior, so every existing fiber is unchanged and apps opt up explicitly. This PR ships the mechanism only. Flipping the default toOwnersOrParticipants(restoring the declared gate) is a breaking, security-hardening decision deliberately reserved for maintainers (RFC §3.4 / §6 Q1) — it would break the "counterparty can sign" patternMultiPartyTransitionSigningSuiteencodes, so it must come with an engine-version bump + migration window + reconciling that suite. Not done here.F6 — auto-declare static
machines.$idread dependenciesStaticDependencyScan.staticMachineRefswalks a transition's guard/effect AST and returns every literally-referencedmachines.<uuid>id;FiberEvaluatorunions those into the runtime dependency set handed toContextProvider.buildContext. Kills the silent-nulltrap (read a cross-fiber state without also hand-declaring the dep). A computed target id still needs an explicitdependenciesentry /_addDependency— intentionally uncovered.Invariant compliance (CLAUDE.md)
transitionPolicyisOption/omit-safe — absent ⇒ stripped bydropNulls⇒ byte-identical canonical.PublishVersionSigningCanonicalSuite+2 cases (absent ⇒ byte-identical,set ⇒ round-trips). The F6 scan augments only the runtime dep set and never mutates the signedTransition.dependencies.CombineRejectedin the combiner, never as a block-acceptanceInvalid.owners/authorizedSignersrecord fields — no registry/asset lineage;validateSignedUpdateis untouched.Tests
TransitionPolicyEnforcementSuite(Open applies a non-owner; Owners rejects; OwnersOrParticipants accepts a participant, rejects a stranger) andAutoDependencyScanSuite.PublishVersionSigningCanonicalSuite+2 cases.sharedData/test: 576 passed, 0 failed. The three named existing suites stay green:TransitionOwnerGateDivergenceSuite1/1 (default-Open still applies — the gap is now opt-in closeable),MultiPartyTransitionSigningSuite6/6,PublishVersionSigningCanonicalSuite5/5.scalafmtCheckAllclean.🤖 Generated with Claude Code