Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions docs/architecture/C1-repair-job-authority.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,17 +225,39 @@ an `ExecutionPermit` records — not only operations that write a ref — that
boundary must satisfy the requirements below, and must **fail closed** — refuse
the operation — wherever a required identity cannot be safely established,
wherever resolution cycles or is otherwise indeterminate, or wherever an effective
identity is or dereferences to the protected parent.
identity is or dereferences to a ref the operand's role is not authorized to
denote.

*The protected-parent rule is role-bound.* Protected-parent identity is forbidden
only where it is unauthorized for the operand's role — which is every role but
one. The effective mutation target of a `repair.commit` or a `repair.push`, and a
`repair.change_request` `sourceRef`, must each be the authorized repair ref, so
for all three an effective identity that is or dereferences to the protected
parent is a refusal. A `repair.change_request` `targetRef` is the single operand
whose *required* effective identity **is** the protected parent ref — the same
operand C1's string layer already singles out as the only one that may name it —
so for that role, and only that role, reaching the protected parent is the
authorized outcome and reaching anything else is the refusal. Stated role-blind
instead, the rule would forbid the one direction the quarantine depends on. No
role widens past this: an operand authorized to denote the protected parent as a
change-request *target* acquires no authority to denote it anywhere else, and the
exemption never reaches an operand that would mutate the parent.

*Which identity is compared.* The isolation question is about the **effective
ref-name referent** — the terminal ref reached by resolving a symbolic-ref chain —
not about commit-object identity. A freshly created repair branch may legitimately
point at the **same commit object** as the protected parent until its first repair
commit, so distinct commit OIDs are neither necessary nor sufficient: two
different branch refs may share one commit OID, and commit-object equality does not
make two refs the same authority target. The boundary must detect and reject a
symbolic or effective ref-name identity that aliases the protected parent, and
must not rest the check on whether two refs currently resolve to the same commit.
make two refs the same authority target. The boundary must therefore compare
effective ref-name referents, and must not rest the check on whether two refs
currently resolve to the same commit. What that comparison must *yield* is fixed
by the operand's role: for an operand whose required identity is the authorized
repair ref, a symbolic or effective ref-name identity that aliases the protected
parent must be detected and rejected; for the one operand whose required identity
is the protected parent ref — the `repair.change_request` `targetRef` — the alias
to detect and reject is the converse one, an effective identity that is not the
protected parent ref.

*Binding the effective mutation target.* A resolved ref *name* is not the target a
mutation will advance, and the boundary must bind the two before it acts:
Expand Down
17 changes: 10 additions & 7 deletions src/domain/repair-job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,13 +527,16 @@ function endsWithDotLockSuffix(value: string, start: number, end: number): boole
* protected parent's commit OID — and bind the effective mutation target it will
* actually advance: the worktree's effective `HEAD` referent for a commit, and the
* effective destination ref for a push. It must **fail closed** — refusing the
* operation — if that effective identity is or dereferences to the protected
* parent, if it changes between comparison and update, or if it cannot be safely
* established; a resolve-then-mutate pre-check is not itself atomic, so the
* invariant is enforced at the mutation/receiving boundary. Nothing here acquires
* git invocation, filesystem access, a subprocess, or network to decide it. See
* `docs/architecture/C1-repair-job-authority.md`, "What canonical ref names do
* and do not prove".
* operation — if that effective mutation target is or dereferences to the
* protected parent, if it changes between comparison and update, or if it cannot
* be safely established; a resolve-then-mutate pre-check is not itself atomic, so
* the invariant is enforced at the mutation/receiving boundary. That refusal is
* bound to the operand's role rather than being a blanket ban on the protected
* parent's identity: a `repair.change_request` `targetRef` is *required* to reach
* the protected parent ref, and fails closed when it reaches anything else.
* Nothing here acquires git invocation, filesystem access, a subprocess, or
* network to decide it. See `docs/architecture/C1-repair-job-authority.md`,
* "What canonical ref names do and do not prove".
*
* The value is returned exactly as supplied, or not at all. No normalisation,
* no prefixing, no case folding: a boundary that repaired the spelling would be
Expand Down
Loading