docs(L11): ADR-0161 — HITL async queue (proposed) (#291)
Answers all eight L11 sub-questions by selecting the narrowest commitment compatible with existing ADR-0057 / 0151 / 0152 / 0155 machinery and the ratify-proposal workflow. Headline decisions: - Queue is a DERIVED VIEW over teaching/proposals/proposals.jsonl ∪ contemplation/runs/*.json. No new persistence file. - Queue identifier = proposal_id (deterministic over content per ADR-0151). States: ADR-0057's existing alphabet. - Three operator surfaces: GitHub PR (inspect-only, mobile), workflow_dispatch (accept|reject|withdraw, mobile), local CLI (audit-grade authority). PR-merge admits; it does not ratify. - Engine keeps serving turns while items are pending; pending proposals are observable but never active truth; proposal-on- proposal dependencies forbidden. - Pending cap 256. Dedup by deterministic proposal_id. No wall-clock expiry — staleness is measured in proposals, not seconds. Full queue emits a typed `queue_full` report instead of silently dropping. - Only the repo owner ratifies; workflow path enforces an actor allow-list and fails closed. Every transition records ratifier_kind, actor, commit_sha, workflow_run_id, review_date. Five-step implementation plan included; each step is small, self-contained, and ships its own ADR-compatibility test. Status: proposed. Closes W-009 once implementation lands. Scope discipline: docs-only. No code, no workflow changes, no tests, no ADR ratification yet. Pure prose contract.
This commit is contained in:
parent
8829529ed0
commit
0909ef2782
1 changed files with 513 additions and 0 deletions
513
docs/decisions/ADR-0161-hitl-async-queue.md
Normal file
513
docs/decisions/ADR-0161-hitl-async-queue.md
Normal file
|
|
@ -0,0 +1,513 @@
|
|||
# ADR-0161 — HITL Async Queue (W-009, L11)
|
||||
|
||||
**Status:** Proposed
|
||||
**Date:** 2026-05-26
|
||||
**Author:** Shay
|
||||
**Parent scope:** [L11 — HITL Async Queue Scope](./L11-hitl-async-queue-scope.md)
|
||||
**Closes:** W-009 (substrate-liveness-ratchet)
|
||||
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
L11 named eight sub-questions the eventual ADR must answer. ADR-0057
|
||||
already pinned proposal eligibility, replay-equivalence, the
|
||||
`pending → accepted | rejected | withdrawn` state machine, and the
|
||||
append-only proposal log. ADR-0151 made `proposal_id` deterministic
|
||||
over (candidate_id, chain). ADR-0152 closed the engine-authored
|
||||
proposal loop end-to-end. ADR-0155 added a CI contemplation runner
|
||||
that proposes via PR review. `.github/workflows/ratify-proposal.yml`
|
||||
exposes `accept_proposal` over `workflow_dispatch` so the operator can
|
||||
ratify from a phone.
|
||||
|
||||
What is still missing is a queue *shape* — a named, replayable view
|
||||
over those existing append-only sources, plus the minimum new
|
||||
machinery needed for backpressure, mobile-feasible inspection, and
|
||||
full state-transition (`reject` and `withdraw`) from the same surface
|
||||
that ratifies. This ADR answers L11's eight sub-questions by
|
||||
selecting from the menu L11 listed, in every case toward the
|
||||
narrowest commitment that still names a testable invariant.
|
||||
|
||||
The principle behind every call below is the same: the queue is **not
|
||||
a new persistence substrate**. It is a deterministic projection of
|
||||
the proposal log and the contemplation-run artifacts the project
|
||||
already commits to. Anything that cannot be derived from those
|
||||
sources is out of scope.
|
||||
|
||||
---
|
||||
|
||||
## Decision summary
|
||||
|
||||
| L11 sub-question | Decision |
|
||||
|---|---|
|
||||
| 1 — Persistent representation | Derived view over `teaching/proposals/proposals.jsonl` ∪ `contemplation/runs/*.json`. Queue identity = `proposal_id`. No new persistence file. |
|
||||
| 2 — Operator interaction surface | Three surfaces, ranked: GitHub PR (mobile-primary, inspect-only), `workflow_dispatch` (mobile-primary, accept/reject/withdraw), local CLI (authoritative). PR-merge is admission, not ratification. |
|
||||
| 3 — Engine behavior while pending | Engine keeps serving turns. Pending proposals are observable but never active truth. No proposal-on-proposal dependencies. |
|
||||
| 4 — Bounds and backpressure | Pending-count cap of **256**. Dedup by deterministic `proposal_id`. No wall-clock expiry. When full, contemplation runner emits a typed `queue_full` report instead of a new proposal. |
|
||||
| 5 — Trust boundary + ratification log | Only the repo owner ratifies. Every transition appends a record carrying `ratifier_kind`, `actor`, `commit_sha`, and (for workflow path) `workflow_run_id`. CI may stage; CI may not ratify. |
|
||||
|
||||
---
|
||||
|
||||
## Decision detail
|
||||
|
||||
### 1. Persistent representation
|
||||
|
||||
The queue is a **derived view** over two append-only sources that
|
||||
already exist on disk and in git history:
|
||||
|
||||
- `teaching/proposals/proposals.jsonl` — the canonical proposal log
|
||||
defined by ADR-0057. Carries `proposal`, `replay`, `transition`,
|
||||
and `accepted_corpus_append` events.
|
||||
- `contemplation/runs/*.json` — CI-emitted contemplation reports
|
||||
defined by ADR-0155. Each report carries one proposal candidate
|
||||
and its replay evidence.
|
||||
|
||||
No third file is introduced.
|
||||
|
||||
**Queue identifier.** A queue item is identified by `proposal_id`
|
||||
(deterministic SHA-256 over `(candidate_id, proposed_chain)` per
|
||||
ADR-0151). Queue items and proposals are 1:1. A contemplation report
|
||||
that has not yet been ingested by `propose_from_candidate` is a
|
||||
*pre-queue artifact*; it becomes a queue item only when its
|
||||
`proposal_id` appears in `proposals.jsonl`.
|
||||
|
||||
**Required derived fields.** For each queue item the projection
|
||||
exposes:
|
||||
|
||||
| Field | Source |
|
||||
|---|---|
|
||||
| `proposal_id` | proposals.jsonl `proposal` event |
|
||||
| `source_kind` | proposals.jsonl `proposal.source.kind` |
|
||||
| `source_id` | proposals.jsonl `proposal.source.source_id` |
|
||||
| `proposed_chain` | proposals.jsonl `proposal.proposed_chain` |
|
||||
| `replay_evidence` | proposals.jsonl `replay` event (most recent) |
|
||||
| `state` | last `transition.to` for this `proposal_id`, or `"pending"` if absent |
|
||||
| `review_history` | full ordered list of `transition` events |
|
||||
| `contemplation_report_path` | `contemplation/runs/*.json` whose `proposal_id` matches, if any |
|
||||
|
||||
The projection is a pure function of the two source files. Replay
|
||||
of the proposal log reconstructs the queue byte-identical.
|
||||
|
||||
**State enumeration.** The state set is **exactly** ADR-0057's
|
||||
existing alphabet — `pending | accepted | rejected | withdrawn`.
|
||||
No new states. "Stale", "superseded", "expired", and "duplicate" are
|
||||
**not** queue states; they are conditions detectable at submission or
|
||||
review time (see §4) and recorded as a `rejected` transition with a
|
||||
typed reason in the `note` field.
|
||||
|
||||
**No deletion.** Append-only. All historical events remain visible
|
||||
under `core teaching proposals --include-history`.
|
||||
|
||||
---
|
||||
|
||||
### 2. Operator interaction surface
|
||||
|
||||
Three operator surfaces exist. Each has a distinct role. None is
|
||||
optional; together they satisfy L11's "mobile-feasible" constraint
|
||||
while preserving the local CLI as the audit-grade authority.
|
||||
|
||||
#### Surface A — GitHub PR (mobile-primary, inspect-only)
|
||||
|
||||
ADR-0155's contemplation workflow opens a PR whose diff is a single
|
||||
`contemplation/runs/<timestamp>.json`. The PR body now also
|
||||
**embeds the queue summary**: pending count, this proposal's
|
||||
`proposal_id`, replay-equivalence outcome, and the chain in
|
||||
human-readable form.
|
||||
|
||||
The operator inspects from the GitHub mobile app. **Merging the PR
|
||||
admits the proposal to the queue. It does not ratify.** This
|
||||
separation matters: merging is "the artifact is now part of the
|
||||
audit trail"; ratifying is "this artifact mutates the corpus".
|
||||
|
||||
#### Surface B — workflow_dispatch (mobile-primary, transition-capable)
|
||||
|
||||
`.github/workflows/ratify-proposal.yml` currently exposes
|
||||
`accept_proposal` only. This ADR extends it to a single workflow
|
||||
parameterized by `action ∈ {accept, reject, withdraw}`. Invocation
|
||||
from the GitHub mobile app provides a phone-feasible path to **every**
|
||||
state transition, not only acceptance.
|
||||
|
||||
Every workflow run records, into the same `proposals.jsonl` event it
|
||||
appends:
|
||||
|
||||
```json
|
||||
{
|
||||
"event": "transition",
|
||||
"proposal_id": "...",
|
||||
"to": "accepted|rejected|withdrawn",
|
||||
"note": "<operator_note>",
|
||||
"ratifier_kind": "workflow_dispatch",
|
||||
"actor": "<github.actor>",
|
||||
"commit_sha": "<github.sha>",
|
||||
"workflow_run_id": "<github.run_id>",
|
||||
"review_date": "YYYY-MM-DD"
|
||||
}
|
||||
```
|
||||
|
||||
#### Surface C — local CLI (authoritative)
|
||||
|
||||
`core teaching review <proposal_id> --accept|--reject|--withdraw`
|
||||
remains the audit-grade authority. Records use
|
||||
`ratifier_kind: "cli"` and carry the operator's OS username and the
|
||||
local `HEAD` SHA at the moment of ratification.
|
||||
|
||||
Identical preconditions hold across surfaces B and C:
|
||||
|
||||
1. `proposal_id` exists in the log.
|
||||
2. Current state is `pending`.
|
||||
3. `replay_evidence.replay_equivalent` is `true`.
|
||||
4. Acting actor matches the repo-owner allow-list (see §5).
|
||||
|
||||
A workflow that violates any precondition fails closed with a
|
||||
non-zero exit and emits no transition event. The proposal stays
|
||||
`pending`.
|
||||
|
||||
#### New read-only surfaces
|
||||
|
||||
Two new CLI commands expose the queue projection:
|
||||
|
||||
- `core teaching queue list [--state pending|accepted|rejected|withdrawn|all]`
|
||||
— prints `proposal_id`, source kind, age (in proposals, not
|
||||
wall-clock — see §4), replay status, and current state.
|
||||
- `core teaching queue show <proposal_id>` — prints the full derived
|
||||
record including `review_history` and the contemplation-report
|
||||
reference if one exists.
|
||||
|
||||
Both are pure projections; neither mutates state.
|
||||
|
||||
---
|
||||
|
||||
### 3. Engine behavior while pending
|
||||
|
||||
The engine keeps running. ADR-0146/0150/0152 already commit to this;
|
||||
this ADR makes it precise for queue semantics.
|
||||
|
||||
- **Live turns.** Pending proposals do not participate in grounding,
|
||||
recall, proposition-graph admissibility, or eval scoring. They are
|
||||
invisible to `chat.runtime.ChatRuntime.chat`.
|
||||
- **Continued production.** The engine may keep producing new
|
||||
proposals while earlier ones are pending, subject to §4 backpressure.
|
||||
- **No proposal-on-proposal dependencies.** A proposal whose
|
||||
`proposed_chain` semantically depends on another *pending* proposal's
|
||||
ratified state is rejected at submission with reason
|
||||
`dependent_on_pending`. Dependencies between proposals create
|
||||
ratification ordering constraints that quietly couple HITL choices;
|
||||
forbidding them keeps every ratification independent. If a chain
|
||||
genuinely depends on another, the dependent proposal is re-proposed
|
||||
*after* the dependency lands.
|
||||
- **Replay across ratification.** Work produced before a
|
||||
ratification replays under the pre-ratification corpus. Work
|
||||
produced after replays under the post-ratification corpus. The
|
||||
proposal log preserves the order so this remains deterministic.
|
||||
|
||||
---
|
||||
|
||||
### 4. Bounds and backpressure
|
||||
|
||||
The queue has a hard cap on **pending** items. Accepted, rejected,
|
||||
and withdrawn items do not count toward the cap.
|
||||
|
||||
#### Pending cap
|
||||
|
||||
**Cap: 256 pending proposals.**
|
||||
|
||||
Rationale: contemplation can run nightly; replay equivalence is the
|
||||
expensive part of producing a proposal, but human review is the
|
||||
expensive part of clearing one. 256 ≈ a year of nightly proposals if
|
||||
the operator clears one per day on average. Any higher and the
|
||||
operator's mental model of "what is pending" stops fitting in human
|
||||
attention; any lower and a short CI burst could refuse work the
|
||||
operator would have wanted to see. This is the only magic number in
|
||||
the ADR; it is operator-tunable via repo variable
|
||||
`CORE_HITL_PENDING_CAP` and defaults to 256 when the variable is
|
||||
absent. The default change is itself a reviewed change (this ADR);
|
||||
the variable is for *raising* the cap, not lowering it below default.
|
||||
|
||||
#### Dedup
|
||||
|
||||
A proposal whose `proposal_id` already exists in the log is rejected
|
||||
at submission as `duplicate`. Because `proposal_id` is deterministic
|
||||
over content (ADR-0151), this is a content-based dedup, not a
|
||||
timestamp dedup. Replay of the same candidate produces the same
|
||||
`proposal_id` and is silently coalesced.
|
||||
|
||||
#### Expiry
|
||||
|
||||
**There is no wall-clock expiry.** Pending proposals stay pending
|
||||
until the operator transitions them. Wall-clock expiry would couple
|
||||
queue state to runner time and break deterministic replay. Operator
|
||||
withdrawal is the only path out of `pending` other than accept/reject.
|
||||
|
||||
#### Full-queue behavior
|
||||
|
||||
When `pending_count >= cap`, the contemplation runner emits a typed
|
||||
`queue_full` report instead of a new proposal:
|
||||
|
||||
```json
|
||||
{
|
||||
"report_kind": "queue_full",
|
||||
"pending_count": <N>,
|
||||
"cap": <C>,
|
||||
"candidates_skipped": [{"candidate_id": "...", "reason": "queue_full"}, ...]
|
||||
}
|
||||
```
|
||||
|
||||
This is written to `contemplation/runs/<timestamp>.json` and opened
|
||||
as a PR exactly like a normal contemplation report. The PR body
|
||||
makes the full state visible to the operator on their phone. No
|
||||
proposal is silently dropped: the `candidate_id` of every skipped
|
||||
candidate is recorded so a future run (after the operator clears
|
||||
queue space) can re-emit it.
|
||||
|
||||
#### Age (in proposals, not wall-clock)
|
||||
|
||||
Queue listing exposes an `age_proposals` integer — the number of
|
||||
*subsequent* proposals appended to the log after this one entered
|
||||
`pending`. This is a replayable, deterministic notion of staleness.
|
||||
Wall-clock time is recorded in events but never load-bearing for
|
||||
queue ordering or backpressure.
|
||||
|
||||
---
|
||||
|
||||
### 5. Trust boundary and ratification log
|
||||
|
||||
#### Who may ratify
|
||||
|
||||
Only the repo owner. Enforcement:
|
||||
|
||||
- **Surface B (workflow_dispatch).** The workflow's `if:` guard
|
||||
rejects any `github.actor` not in the repo's `CORE_RATIFIERS`
|
||||
variable (comma-separated GitHub logins). When the variable is
|
||||
unset, the default ratifier set is `${{ github.repository_owner }}`
|
||||
alone. The job fails closed with a clear log message if the actor
|
||||
is unauthorized.
|
||||
- **Surface C (local CLI).** No additional check beyond the existing
|
||||
local filesystem authority. The CLI cannot be exercised remotely;
|
||||
possession of a local working copy is the trust boundary.
|
||||
|
||||
CI workflows (contemplation runner, lane-SHA verifier, smoke gate,
|
||||
etc.) **cannot ratify**. They have no path to `accept_proposal`.
|
||||
They may stage artifacts and open PRs, nothing more.
|
||||
|
||||
#### Ratification record
|
||||
|
||||
Every transition appends a single JSONL event to `proposals.jsonl`:
|
||||
|
||||
```json
|
||||
{
|
||||
"event": "transition",
|
||||
"proposal_id": "<sha256>",
|
||||
"to": "accepted|rejected|withdrawn",
|
||||
"note": "<free-text>",
|
||||
"ratifier_kind": "cli|workflow_dispatch",
|
||||
"actor": "<github.actor | os.user>",
|
||||
"commit_sha": "<HEAD at transition>",
|
||||
"workflow_run_id": "<github.run_id or null>",
|
||||
"review_date": "YYYY-MM-DD"
|
||||
}
|
||||
```
|
||||
|
||||
`actor`, `commit_sha`, and `workflow_run_id` are recorded for audit
|
||||
but are **not load-bearing for state reconstruction**. Replay of the
|
||||
log requires only `proposal_id` and `to`. This keeps the replay
|
||||
substrate small while making audit forensics complete.
|
||||
|
||||
#### Replay invariants
|
||||
|
||||
Given `proposals.jsonl` and `contemplation/runs/*.json`, the queue
|
||||
state at any historical point is reconstructible byte-identical by
|
||||
folding events in order. The new fields (`ratifier_kind`, `actor`,
|
||||
`commit_sha`, `workflow_run_id`) appear in audit projections but not
|
||||
in the trace hash inputs. Existing trace_hash invariants from
|
||||
ADR-0153 are preserved.
|
||||
|
||||
---
|
||||
|
||||
## Out of scope (deferred)
|
||||
|
||||
This ADR scopes only the HITL async queue. It does not commit to:
|
||||
|
||||
- a Workbench API or UI surface (ADR-0160 W-026..W-031);
|
||||
- engine-identity continuity (`project-engine-identity-candidate`,
|
||||
shelved — un-shelve only if cross-reboot ratifier identity becomes
|
||||
load-bearing);
|
||||
- recognizer-storage durability (separate ADR);
|
||||
- pack mutation queue (packs remain reviewed-ratify-only outside this
|
||||
queue);
|
||||
- safety / ethics ratification semantics;
|
||||
- a queue prioritization heuristic (queue is FIFO by log order);
|
||||
- automatic dependency-chasing across pending proposals;
|
||||
- Slack / email / push-notification delivery;
|
||||
- a daemon or background worker;
|
||||
- a database-backed queue.
|
||||
|
||||
The queue presented here is the **minimum** structure that satisfies
|
||||
L11. Each deferred item can become its own ADR without disturbing
|
||||
this one.
|
||||
|
||||
---
|
||||
|
||||
## Implementation plan
|
||||
|
||||
Five small PRs, each a self-contained step, none of which mutate
|
||||
existing recorded queue history:
|
||||
|
||||
### Step 1 — `core teaching queue` read commands
|
||||
|
||||
- New module `teaching/queue.py` exposing a pure `derive_queue(log)`
|
||||
function that returns the projection in §1.
|
||||
- New CLI subcommand `core teaching queue list|show` wired in
|
||||
`core/cli.py`.
|
||||
- Tests: pure derivation over fixture proposals.jsonl; states match
|
||||
ADR-0057's alphabet; replay-equivalence in derivation.
|
||||
- **No mutation paths.**
|
||||
|
||||
### Step 2 — Backpressure (pending-count cap)
|
||||
|
||||
- `propose_from_candidate` consults pending count via
|
||||
`teaching/queue.derive_queue` and emits a `queue_full` report
|
||||
instead of a new proposal when the cap is reached.
|
||||
- `contemplation/runs/<timestamp>.json` schema extended with
|
||||
`report_kind ∈ {"learning_arc", "queue_full"}` (default
|
||||
`"learning_arc"` for back-compat).
|
||||
- Repo variable `CORE_HITL_PENDING_CAP` honored; default 256.
|
||||
- Tests: synthetic full-queue triggers `queue_full` report;
|
||||
candidate_id of every skipped item is recorded; replay still
|
||||
byte-identical.
|
||||
|
||||
### Step 3 — Submission-time invariants
|
||||
|
||||
- `propose_from_candidate` rejects duplicate `proposal_id` with reason
|
||||
`duplicate` (already enforced; this step adds the explicit recorded
|
||||
reason).
|
||||
- `propose_from_candidate` rejects `dependent_on_pending` proposals.
|
||||
Heuristic: chain whose `subject` or `object` lemma is a substring
|
||||
of any pending proposal's `proposed_chain` is considered dependent;
|
||||
the conservative check fails loud and the proposal is re-emitted
|
||||
after the dependency lands.
|
||||
- Tests for both rejection paths.
|
||||
|
||||
### Step 4 — Extend ratification workflow to reject/withdraw
|
||||
|
||||
- `.github/workflows/ratify-proposal.yml` gains an `action` input
|
||||
(`accept | reject | withdraw`) and dispatches to the corresponding
|
||||
CLI subcommand.
|
||||
- Workflow guard enforces `actor ∈ CORE_RATIFIERS` (defaults to repo
|
||||
owner if variable is unset).
|
||||
- Transition record includes `ratifier_kind: "workflow_dispatch"`,
|
||||
`actor`, `commit_sha`, `workflow_run_id`, `review_date`.
|
||||
- Mirror updates to `core teaching review` so CLI records
|
||||
`ratifier_kind: "cli"` symmetrically.
|
||||
- Tests: precondition failures emit no transition event; unauthorized
|
||||
actor fails closed.
|
||||
|
||||
### Step 5 — Embed queue summary in contemplation PR body
|
||||
|
||||
- The contemplation workflow's PR body now includes the queue summary
|
||||
(pending count, cap, this proposal_id, replay outcome,
|
||||
human-readable chain).
|
||||
- Operator inspecting from mobile sees full queue context without
|
||||
opening the JSON.
|
||||
- No corpus or ratification effect.
|
||||
|
||||
Each PR ships with its own ADR-compatibility statement, lane tests,
|
||||
and read-only invariant assertion (no mutation outside
|
||||
`proposals.jsonl` and `contemplation/runs/`).
|
||||
|
||||
---
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
This ADR is ratifiable when:
|
||||
|
||||
1. The queue projection is a pure function of the two source files,
|
||||
with a test that proves the projection is byte-identical across a
|
||||
randomized event-order replay (the source files are append-only,
|
||||
so order is fixed in practice — the test confirms the projection
|
||||
does not depend on hidden state).
|
||||
2. The pending-count cap fires deterministically in a synthetic test
|
||||
that pre-populates `proposals.jsonl` with 256 pending entries; the
|
||||
257th submission produces a `queue_full` report and no proposal.
|
||||
3. Every transition event records `ratifier_kind`, `actor`, and
|
||||
`commit_sha`, asserted by tests against both CLI and workflow
|
||||
surfaces.
|
||||
4. The workflow's actor guard fails closed in a CI test that fakes a
|
||||
non-allowlisted `github.actor`.
|
||||
5. `core teaching queue list` and `... show` succeed against the
|
||||
current `teaching/proposals/proposals.jsonl` on `main` without
|
||||
mutating any file (snapshot assertion).
|
||||
|
||||
---
|
||||
|
||||
## Consequences
|
||||
|
||||
### Positive
|
||||
|
||||
- Closes W-009, the last open substrate-liveness ratchet item.
|
||||
- The queue exists without introducing a new persistence file.
|
||||
- Mobile ratification path covers all three transitions, not just
|
||||
accept.
|
||||
- Backpressure is bounded and deterministic — no silent drops, no
|
||||
unbounded growth.
|
||||
- Audit forensics gain `actor` / `commit_sha` / `workflow_run_id`
|
||||
without changing replay semantics or trace_hash inputs.
|
||||
|
||||
### Negative
|
||||
|
||||
- The pending cap is a single magic number; raising it remotely
|
||||
requires the operator to change a repo variable from a phone. This
|
||||
is an accepted trade for keeping the queue projection a pure
|
||||
function of two files.
|
||||
- Forbidding proposal-on-proposal dependencies will occasionally
|
||||
force a re-emission of a chain after its dependency lands. This
|
||||
is intentional: dependent ratification ordering is the wrong
|
||||
failure mode to bake in.
|
||||
- Symmetry between CLI and workflow surfaces enlarges the surface
|
||||
area for `accept_proposal`'s preconditions; tests must enforce
|
||||
identical precondition behavior across both paths.
|
||||
|
||||
### Risks
|
||||
|
||||
- `ratifier_kind` and `actor` are recorded but not used for
|
||||
authorization beyond the workflow's `if:` guard. Local CLI trust
|
||||
remains "possession of the working copy". If the threat model
|
||||
later admits multi-operator scenarios, a follow-up ADR must add a
|
||||
CLI-side identity check; this ADR explicitly does not.
|
||||
- `dependent_on_pending` detection uses lemma-substring heuristics.
|
||||
False positives reject genuinely independent chains. False
|
||||
negatives admit dependent chains that ratification ordering will
|
||||
surface later. The conservative choice is to err toward false
|
||||
positives (over-reject), since rejected proposals can be
|
||||
re-emitted; the alternative silently couples ratifications.
|
||||
|
||||
---
|
||||
|
||||
## Cross-references
|
||||
|
||||
- [L11 — HITL Async Queue Scope](./L11-hitl-async-queue-scope.md)
|
||||
- [L10 — Runtime Model Scope](./L10-runtime-model-scope.md)
|
||||
- [ADR-0057 — Teaching-Chain Proposal + Review + Replay-Equivalence Gate](./ADR-0057-teaching-chain-proposal-review.md)
|
||||
- [ADR-0151 — Load-time auto-proposal pipeline](./ADR-0151-auto-proposal-pipeline.md)
|
||||
- [ADR-0152 — Learning-arc demo (proof corridor)](./ADR-0152-learning-arc-demo.md)
|
||||
- [ADR-0153 — TurnEvent.trace_hash back-stamp](./ADR-0153-turn-event-trace-hash-backstamp.md)
|
||||
- [ADR-0155 — CI contemplation runner](./ADR-0155-ci-contemplation-runner.md)
|
||||
- [ADR-0156 — Atomic engine-state checkpoint](./ADR-0156-atomic-engine-state-checkpoint.md)
|
||||
- [ADR-0157 — Revision-mismatch warning](./ADR-0157-revision-mismatch-warning.md)
|
||||
- [ADR-0158 — Reboot-event audit trail](./ADR-0158-reboot-event-audit.md)
|
||||
- [`.github/workflows/ratify-proposal.yml`](../../.github/workflows/ratify-proposal.yml)
|
||||
- [CLAUDE.md](../../CLAUDE.md) — deterministic replay, exact recall, proposal-only learning, no hidden state.
|
||||
|
||||
### Memory cross-references
|
||||
|
||||
- [[thesis-decoding-not-generating]] — the queue must teach the
|
||||
engine *to find* better-ratified evidence, not just store another
|
||||
found thing. Backpressure-as-`queue_full`-report rather than
|
||||
silent-drop honors this.
|
||||
- [[feedback-adr-cross-reference-discipline]] — every decision above
|
||||
selects from existing ADRs and workflows; no parallel mechanism is
|
||||
introduced.
|
||||
- [[feedback-address-critiques-dont-waive]] — L11's eight sub-questions
|
||||
are answered in order, not deferred.
|
||||
- [[project-engine-identity-candidate]] — remains shelved; the
|
||||
`actor` field in transition records covers the audit need without
|
||||
un-shelving engine-identity work.
|
||||
Loading…
Reference in a new issue