aepkit 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,103 @@
1
+ # Failure Modes and Worked Example
2
+
3
+ Part of the `auditor-executor-protocol` skill. Load when auditing a delivery or looking for a filled-in run. Section names in
4
+ quotes ("Rules of engagement", "Auditing", ...) refer to `SKILL.md` unless they are in
5
+ this file.
6
+
7
+ ## Failure modes seen in practice
8
+
9
+ - **Self-expansion.** The Executor implements phases marked "do not start." Work
10
+ arrives with no checkpoints between phases; a defect in an early one gets built on
11
+ before anyone looks.
12
+ - **Zero stops.** An empty "Blocked" section across dozens of tasks means ambiguities
13
+ were resolved silently, not that none existed.
14
+ - **Letter over intent.** The task says "add a check for case X"; a check appears, it
15
+ passes, and the condition X exists to detect is routed around by fixture ordering or
16
+ test isolation. Anticipate this by naming the expected failure in the task itself.
17
+ - **Evidence-free `DONE`.** Treat as `FAILED`. Say so in the reporting rules up front.
18
+ - **The Auditor shrinks the goal.** Asked for a whole outcome, the plan delivers a
19
+ slice of it and calls the rest "follow-up," backed by a risk/ROI argument. Shrinking
20
+ the goal is never authorized; splitting it into phases is fine, as long as the goal
21
+ is met. Big goals get more phases, never a smaller goal — later phases are part of
22
+ the run, not a follow-up.
23
+ - **Silent model inheritance.** A subagent launched without an explicit model runs on
24
+ the Auditor's own model. Nothing fails; the rule is just broken on every task. Pass
25
+ it every time.
26
+ - **Guided by habit.** In Autonomous mode, the Auditor ends a turn after a `PASS` to
27
+ "report," or asks the owner a question the charter already lets it decide. Each one
28
+ costs the owner a message and adds nothing.
29
+ - **A defect ships and nobody owns re-checking its blast radius.** A task changes what
30
+ an existing field means; every other reader of that field is now a latent bug, and
31
+ the person who finds it is usually a different, unrelated task that happens to hit
32
+ it — not a re-audit of the original task. Grep for every reader before signing off,
33
+ not after something breaks.
34
+ - **A change primes something to fire on its own before anyone can see or stop it.** A
35
+ migration or config change that alters what triggers an automated write can leave
36
+ the system armed to act — at scale, on real data — the moment its ordinary trigger
37
+ next runs, with no one having pressed a button and no UI yet built to see or cancel
38
+ it. Check the state the change leaves behind, not only the correctness of the new
39
+ code path.
40
+
41
+ ## Worked example
42
+
43
+ Everything below is fictional and sanitized. It shows the shape of each artifact, not
44
+ content to copy. Names, commands and risks in a real run come from that project.
45
+
46
+ **Plan:** "Notifications as a standalone service" in a web shop. Goal set by the owner:
47
+ every notification leaves the monolith. Acceptance criteria AC1-AC4. Phases P0-P5, with
48
+ P0-P2 expanded into tasks and P3-P5 fixed in scope, expanded by the Auditor at each gate.
49
+ Mode: Autonomous (governance decision D9 in the plan of record).
50
+
51
+ **Rules-of-engagement block (item 8)**, as it would appear in each handoff:
52
+
53
+ ```
54
+ - One task at a time.
55
+ - Verification = run the command and the negative controls, not read the code.
56
+ - Fetch and compare against the remote branch before starting and before pushing.
57
+ - <project's quality-gate command> exits 0 before any push.
58
+ - Every commit to the main branch bumps the version with <project's version script>.
59
+ - No AI tool co-authorship on commits.
60
+ ```
61
+
62
+ **Auditor brief (abridged):**
63
+
64
+ ```
65
+ ROLE: Auditor of plan "Notifications as a standalone service". You do not write feature
66
+ code. You run this in Autonomous mode: launch Executors as subagents, audit each
67
+ delivery by re-running it, resolve their questions, expand P3-P5 once the previous gate
68
+ is APPROVED. Follow the auditor-executor-protocol skill.
69
+
70
+ AUTONOMY (D9; "Coordination and autonomy" section of the guide):
71
+ - You decide anything the documents leave open; amend decisions by annex with evidence.
72
+ You never amend AC1-AC4 or reduce scope.
73
+ - BLOCKED → decision entry in the log; the task continues.
74
+ - Permissions needing the owner: one batched request. Short report per closed phase.
75
+ - ONLY reasons to interrupt the owner:
76
+ 1. Reducing or reinterpreting AC1-AC4.
77
+ 2. Deleting production data without a verified, restorable backup.
78
+ 3. A real email or SMS sent to a customer.
79
+ 4. Charges, refunds, or billing changes not proven equivalent.
80
+ 5. Production down after a deploy with no successful rollback.
81
+ 6. An exposed secret.
82
+ 7. Force-push or disabling CI.
83
+
84
+ EXECUTOR MODEL ASSIGNMENT: small/fast tier for P0-T1, P1-T3, P2-T4 (listed commands,
85
+ bump, gate, push). Mid tier for the rest. Top tier never. Model explicit on every
86
+ launch; if a small-tier task goes off-script, relaunch the whole task on the mid tier.
87
+
88
+ STATE: clean tree, plan committed and pushed. First task: P0-T1 on the small/fast tier.
89
+
90
+ GOAL (non-negotiable): no notification leaves the monolith. RUN COMPLETE only with
91
+ P5-G1 APPROVED, which proves AC1-AC4.
92
+
93
+ WHAT'S VERIFIED AND WHAT ISN'T:
94
+ - Verified (command in the plan): all 14 send sites in the inventory.
95
+ - Not verified: whether the SMS provider accepts idempotency keys (P2-T2 measures it).
96
+
97
+ TRAPS: "doesn't send" checks that pass because the mock was never registered; negative
98
+ controls restored with a command that wipes other uncommitted work; a small-tier task
99
+ that patches an unexpected surprise itself instead of escalating.
100
+
101
+ FIRST STEP: read the three documents, confirm the log is empty, launch P0-T1 on the
102
+ small/fast tier.
103
+ ```
@@ -0,0 +1,133 @@
1
+ # Handoffs
2
+
3
+ Part of the `auditor-executor-protocol` skill. Load when handing a task to an Executor or writing a remediation order. Section names in
4
+ quotes ("Rules of engagement", "Auditing", ...) refer to `SKILL.md` unless they are in
5
+ this file.
6
+
7
+ ## Handing off a task (Auditor)
8
+
9
+ Writing the execution guide is not the handoff. The Executor's session starts cold — it
10
+ has none of the investigation behind the guide, and "read the execution guide, task
11
+ `<ID>`" is a pointer to an instruction, not the instruction itself. Producing the actual,
12
+ paste-ready message for a fresh Executor session is Auditor work, not something left for
13
+ whoever is relaying the plan to assemble by hand.
14
+
15
+ **The rules-of-engagement block in the template below is item 8, settled when the run
16
+ started** ("Rules of engagement" in `SKILL.md`) — not re-derived here, and not re-asked per
17
+ task. If you're about to write a handoff and item 8 is still blank, that's the actual
18
+ problem: go settle it before drafting the message, don't paste a rule set from a
19
+ different project or a different run to fill the gap. A rule copied in from elsewhere
20
+ either asserts something false about this codebase or hands the Executor a stop it has
21
+ no way to satisfy.
22
+
23
+ ### Handoff template
24
+
25
+ One task per message, addressed to a fresh Executor session with no shared context. Fill
26
+ every section — do not leave "see the execution guide" where a fact belongs.
27
+
28
+ ```
29
+ ROLE: Executor. Work from <EXECUTION_GUIDE> (Phase <n>, `<TASK-ID>`) only; report in
30
+ <COMPLIANCE_LOG>, section `<TASK-ID>` (already exists, empty).
31
+
32
+ [Autonomous mode only:] You are the Auditor's subagent. Questions go as BLOCKED in the
33
+ log and in your final report; you do not address the owner.
34
+
35
+ REPORTED STATE: <what is already DONE in the log, and whether it was audited or only
36
+ self-reported — do not conflate the two>. Do not reopen <prior tasks>.
37
+
38
+ TASK: <TASK-ID> — <imperative title>
39
+ Source: <EXECUTION_GUIDE>, section "<TASK-ID>" in full.
40
+
41
+ Goal: <one sentence — what is true after this that was not before>.
42
+
43
+ Key finding (already verified, do not re-check it): <the concrete fact driving this
44
+ task, with the file/line/command that established it>.
45
+
46
+ Decided points, not reopenable without evidence that contradicts them:
47
+ 1. <decision>
48
+ 2. <decision>
49
+ ...
50
+
51
+ Failure to avoid explicitly: <the specific mistake a context-free Executor would make by
52
+ reflex — copying a neighboring task's filter that doesn't apply here, re-deriving a
53
+ fact that was already established and getting it wrong, etc.>.
54
+
55
+ Verify (literal):
56
+ <exact command>
57
+
58
+ Success, minimum: <what the check(s) must prove, in terms of cases — not "it passes">.
59
+
60
+ Report: <TASK-ID>, in <COMPLIANCE_LOG>, section already created.
61
+
62
+ RULES OF ENGAGEMENT (this run's — confirmed at the start, not a default):
63
+ <the block settled above>
64
+ ```
65
+
66
+ `Key finding` and `Failure to avoid` exist because a fresh Executor has no memory of the
67
+ investigation behind the task — it will make exactly the mistake full context would have
68
+ prevented. Naming the specific reflex to avoid is cheaper than an Executor discovering it
69
+ mid-task.
70
+
71
+ Do not paste a rules-of-engagement block from one project's run into another's handoff
72
+ without re-confirming it applies. It is a per-run artifact, not part of this skill.
73
+
74
+ ## Remediation handoff (Auditor)
75
+
76
+ A verdict is not the deliverable — a well-evidenced `CONDITIONAL` or `REJECTED` that
77
+ ends in prose still leaves the Executor with nothing to act on. This is the
78
+ `Remediation order (annex)` from "The document set": write it, and hand it off the same
79
+ way the first task was handed off, not as a narrative the reader has to translate into
80
+ next steps themselves.
81
+
82
+ ```
83
+ ROLE: Executor. Work from this remediation only; the rest of <EXECUTION_GUIDE> is
84
+ unaffected unless named below. Report in <COMPLIANCE_LOG>, appended under <GATE-ID> —
85
+ do not overwrite the original entry.
86
+
87
+ MODEL: <the original task's, or the next tier up if this is an escalation>.
88
+
89
+ AUDIT RESULT: <Phase/Task> — <CONDITIONAL | REJECTED>. <one line: what was
90
+ independently re-verified and passed, so the Executor knows what not to touch>.
91
+
92
+ BLOCKED: <GATE-ID> — <what's actually wrong, in the Auditor's own re-run terms, not a
93
+ restatement of what the original delivery claimed>.
94
+
95
+ Root cause (verified — carries the command that established it, not reasoned from the
96
+ code): <the mechanism, with file/line and the falsifying probe or command that proved
97
+ it wrong>.
98
+
99
+ Candidate fix — a recommendation, not a decided point; the Auditor has not run it:
100
+ <the shape of a fix. Mark explicitly as unverified — the Executor confirms it, and may
101
+ find a better one, per "a factual claim always is reopenable">.
102
+
103
+ Do not touch: <what already passed and must not be disturbed by this fix — the other
104
+ approved gates or tasks in this delivery>.
105
+
106
+ Verify (literal): <the exact re-run command(s), including re-running the falsifying
107
+ probe that caught this — it must now pass>.
108
+
109
+ Success, minimum: <what must be true afterward — the probe that failed now passes, the
110
+ original suite stays green, nothing named under "Do not touch" moved>.
111
+
112
+ Report: <GATE-ID>, in <COMPLIANCE_LOG>, as a remediation entry.
113
+
114
+ RULES OF ENGAGEMENT: <this run's block>
115
+ ```
116
+
117
+ The "candidate fix, not a decided point" framing matters — the Auditor found the defect
118
+ by running a probe, not by running the fix. Presenting it as settled would violate the
119
+ Auditor's own rule 4 ("The Auditor is bound by rule 4 too" in `SKILL.md`).
120
+
121
+ **No verdict ends the loop by itself if anything is left to run — and "anything left to
122
+ run" is not only "a phase remains" or "a remediation order is needed."** It also covers
123
+ the most common case of all: a plain `PASS` on one task, mid-phase, with something else
124
+ already outstanding — an earlier remediation, the next task in line. That case has no
125
+ name of its own in the Verdicts table of `SKILL.md`, which is exactly why it's the easiest one
126
+ to ship without a handoff: closing with a status sentence that *describes* what's still
127
+ pending, instead of resending the pasteable block for it. Only a genuine "nothing left"
128
+ closes without a handoff. Otherwise: send the outstanding remediation, or the next
129
+ phase's first task, or the handoff already sent and not yet acted on — with the literal
130
+ template from "Remediation handoff" or "Handing off a task" above, in the same message
131
+ as the verdict, never as a sentence describing it. The Executor's next session starts
132
+ cold no matter which verdict just landed; a one-line summary of what's still owed is
133
+ exactly the kind of pointer-not-an-instruction this whole document exists to close.
@@ -0,0 +1,84 @@
1
+ # Writing Tasks and Gates
2
+
3
+ Part of the `auditor-executor-protocol` skill. Load when writing a task or a gate. Section names in
4
+ quotes ("Rules of engagement", "Auditing", ...) refer to `SKILL.md` unless they are in
5
+ this file.
6
+
7
+ ## Writing a task (Auditor)
8
+
9
+ ```
10
+ ### <TASK-ID> — <imperative, one line>
11
+
12
+ **Goal:** one sentence. What is true after this that was not before.
13
+ **Files:** every path the Executor should read or change.
14
+ **Blast radius:** every caller or reader of anything a step renames, empties, deletes, or
15
+ redefines — including a later task's planned work. Empty if genuinely none; never left
16
+ blank.
17
+ **Steps:** numbered. Exact enough that two Executors produce the same thing.
18
+ **Verify:** the literal command, and the output that counts as success.
19
+ **Report:** the task ID.
20
+ ```
21
+
22
+ Rules for the steps:
23
+
24
+ - Encode decisions, do not re-open them. "Polling, not a push channel — this is
25
+ decided, believing otherwise is a stop, not a choice to make while implementing."
26
+ - **Name the failure you expect.** If a field might get overwritten, if a type behaves
27
+ differently across two environments, if a cap is a layout decision and not a data
28
+ one — say so in the task. Most bad output comes from an ambiguity the task's author
29
+ already saw and didn't write down.
30
+ - State what must *not* change alongside what must.
31
+ - **The Blast radius field is not optional decoration — write it before the step, not
32
+ after something breaks.** When a task renames or redefines what an existing field or
33
+ column means, the task text must include the command to find every other reader of
34
+ it, and the Executor must run it and account for every hit, not only the call sites
35
+ the task's file list happened to name. When a step would empty, delete, or replace
36
+ shared code, check whether a *later* task in the same phase was planned to still call
37
+ it — if so, the step is "leave a delegating stub," not "empty it," until the task that
38
+ owns that caller lands. A task's file list is a lower bound on its blast radius,
39
+ discovered by the person who wrote the task before the work started — not the whole
40
+ of it, discovered later by whoever happens to hit the stale or broken reader next.
41
+ - **When a task changes what triggers an automatic action** (a scheduler, a background
42
+ job, a materializer, anything that can fire without a human pressing a button), the
43
+ task must require checking — before shipping — what state the change leaves the
44
+ system in and whether anything is now primed to fire destructively on its next
45
+ ordinary trigger. Passing tests prove the new code path is correct; they do not
46
+ prove nothing is about to run against real data the moment it gets the chance.
47
+
48
+ ## Writing a gate (Auditor)
49
+
50
+ A gate is a claim that can be proven false. "Tests pass" is not a gate. "The
51
+ visibility check was observed failing with the filter removed" is.
52
+
53
+ Every gate names how it is proven. Include, whenever the phase produces a security,
54
+ privacy, or financial-integrity boundary, a **negative control**: the Executor must
55
+ remove the protection, observe the check fail, restore it, and observe it pass. A
56
+ check never seen failing has not been verified. It must also fail for the right
57
+ reason: a syntax error or a missing import fails just as loudly, so the control names
58
+ the failure it expects (the assertion, the status code) and the Auditor checks the
59
+ output shows it. `aepkit negcontrol` runs this sequence and produces a paste-ready
60
+ transcript; `--expect "<regex>"` makes it reject a failure whose output does not match.
61
+
62
+ **A gate defined by more than one command must be re-run in full, not cited from
63
+ whichever half was last checked.** A compound gate closed in one phase by running only
64
+ one of its checks, then cited as "already satisfied" in later phase gates without ever
65
+ re-running the rest, can let real violations accumulate for phases before anyone
66
+ notices. If a gate's own definition lists multiple checks, every phase that claims it as
67
+ satisfied re-runs all of them — a partial citation from an earlier phase does not close
68
+ a compound gate.
69
+
70
+ **A shared test fixture that always uses a simplified shape hides bugs that only appear
71
+ with a realistic one.** A helper that builds request URLs, headers, or IDs for tests
72
+ should default to a realistic shape (a base URL with its own path prefix, a populated
73
+ auth header, a non-empty ID) rather than the minimal shape that's easiest to write —
74
+ otherwise every test built on it passes for the wrong reason. When gating a feature that
75
+ touches an external contract, prove it against at least one realistically-shaped
76
+ fixture, not only the simplified one most unit tests use.
77
+
78
+ **When a decision restricts what one channel may carry, check every other channel
79
+ available for the same call.** A rule like "this value travels only via the field
80
+ scoped for it, never the generic payload" is not proven by testing the transport where
81
+ that rule was enforced — check whether the same data can leak through a sibling channel
82
+ on a transport the restriction was never applied to, especially one that leaves your own
83
+ infrastructure for a third party. A restriction proven on one channel or transport is
84
+ not proven on all of them.
aepkit/status.py ADDED
@@ -0,0 +1,122 @@
1
+ """Tally the compliance log and print what is still open.
2
+
3
+ Two sources are combined per task/gate ID:
4
+
5
+ - the Auditor's verdict: the "Verdict" column of the status board table, or a report
6
+ header whose status is a verdict (APPROVED, CONDITIONAL, REJECTED);
7
+ - the Executor's latest report header (DONE, BLOCKED, FAILED, PENDING).
8
+
9
+ Only APPROVED closes an item. A DONE report without a verdict is self-reported, not
10
+ audited, so it is listed as awaiting audit. When the board and a report header carry
11
+ different verdicts, the item is listed as a conflict and stays open.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import re
17
+ import sys
18
+ from collections import Counter
19
+ from pathlib import Path
20
+
21
+ LOG_HEADER_RE = re.compile(
22
+ r"^###\s+([A-Za-z0-9_.\-]+)\s+[\u2014\u2013\-]\s+([A-Za-z_]+)\s*$", re.MULTILINE
23
+ )
24
+
25
+ VERDICTS = {"APPROVED", "CONDITIONAL", "REJECTED"}
26
+ CLOSED = "APPROVED"
27
+ AWAITING_AUDIT = "AWAITING AUDIT"
28
+ CONFLICT = "CONFLICT"
29
+
30
+
31
+ def _cells(line: str) -> list[str]:
32
+ return [c.strip().strip("`*").strip() for c in line.strip().strip("|").split("|")]
33
+
34
+
35
+ def _board_verdicts(text: str) -> dict[str, str]:
36
+ """ID -> verdict from the first table whose header has "ID" and "Verdict" columns."""
37
+ lines = text.splitlines()
38
+ for i, line in enumerate(lines):
39
+ if not line.lstrip().startswith("|"):
40
+ continue
41
+ header = [c.lower() for c in _cells(line)]
42
+ if "id" not in header or "verdict" not in header:
43
+ continue
44
+ id_col, verdict_col = header.index("id"), header.index("verdict")
45
+ verdicts: dict[str, str] = {}
46
+ for row in lines[i + 1 :]:
47
+ if not row.lstrip().startswith("|"):
48
+ break
49
+ cells = _cells(row)
50
+ if len(cells) <= max(id_col, verdict_col) or set(cells[id_col]) <= set("-: "):
51
+ continue
52
+ verdicts[cells[id_col]] = cells[verdict_col].upper()
53
+ return verdicts
54
+ return {}
55
+
56
+
57
+ def run(target_dir: str) -> int:
58
+ target = Path(target_dir)
59
+ log_path = target / "compliance-log.md"
60
+ if not log_path.exists():
61
+ print(f"error: {log_path} not found.", file=sys.stderr)
62
+ return 2
63
+
64
+ text = log_path.read_text(encoding="utf-8")
65
+
66
+ # IDs in first-seen order; for headers, the last occurrence wins (resubmissions).
67
+ order: dict[str, None] = {}
68
+ reports: dict[str, str] = {}
69
+ header_verdicts: dict[str, str] = {}
70
+ last_header_id = ""
71
+ board = _board_verdicts(text)
72
+ for task_id in board:
73
+ order.setdefault(task_id, None)
74
+ for m in LOG_HEADER_RE.finditer(text):
75
+ task_id, value = m.group(1), m.group(2).upper()
76
+ order.setdefault(task_id, None)
77
+ last_header_id = task_id
78
+ if value in VERDICTS:
79
+ header_verdicts[task_id] = value
80
+ else:
81
+ reports[task_id] = value
82
+
83
+ if not order:
84
+ print("no task entries found in compliance-log.md.")
85
+ return 0
86
+
87
+ states: dict[str, str] = {}
88
+ conflicts: dict[str, str] = {}
89
+ for task_id in order:
90
+ board_verdict = board.get(task_id, "")
91
+ board_verdict = board_verdict if board_verdict in VERDICTS else ""
92
+ header_verdict = header_verdicts.get(task_id, "")
93
+ verdict = board_verdict or header_verdict
94
+ report = reports.get(task_id, "PENDING")
95
+ if board_verdict and header_verdict and board_verdict != header_verdict:
96
+ states[task_id] = CONFLICT
97
+ conflicts[task_id] = (
98
+ f" (status board: {board_verdict}, report header: {header_verdict})"
99
+ )
100
+ elif verdict:
101
+ states[task_id] = verdict
102
+ elif report == "DONE":
103
+ states[task_id] = AWAITING_AUDIT
104
+ else:
105
+ states[task_id] = report
106
+
107
+ counts = Counter(states.values())
108
+ print("Status board:")
109
+ for state, n in sorted(counts.items(), key=lambda kv: (-kv[1], kv[0])):
110
+ print(f" {state:<15} {n}")
111
+
112
+ open_items = [(tid, st) for tid, st in states.items() if st != CLOSED]
113
+ print(f"\n{len(open_items)} open (not APPROVED):")
114
+ for tid, st in open_items:
115
+ report_of_item = reports.get(tid)
116
+ detail = f" (report: {report_of_item})" if report_of_item and st in VERDICTS else ""
117
+ detail = conflicts.get(tid, detail)
118
+ print(f" - {tid}: {st}{detail}")
119
+
120
+ last_id = last_header_id or next(reversed(order))
121
+ print(f"\nMost recent entry: {last_id} ({states[last_id]})")
122
+ return 0
@@ -0,0 +1,37 @@
1
+ # {{PROJECT_NAME}} — Compliance Log
2
+
3
+ > **Evidence of record.** One report and one verdict per task/gate ID. Pre-generate an
4
+ > empty row per ID from the execution guide so nothing gets skipped silently.
5
+ >
6
+ > Maintained by the Auditor after every verdict. Compact repeated open conditions
7
+ > periodically instead of only appending — see the protocol's note on log maintenance.
8
+
9
+ ---
10
+
11
+ ## Status board
12
+
13
+ | ID | Delivery | Verdict | Notes |
14
+ |---|---|---|---|
15
+ | P0-T1 | | `PENDING` | |
16
+ | P0-G1 | | `PENDING` | |
17
+
18
+ ---
19
+
20
+ ## Open conditions
21
+
22
+ None yet.
23
+
24
+ ---
25
+
26
+ ## Reports
27
+
28
+ ### P0-T1 — PENDING
29
+ **Changed:**
30
+ **Verify output:**
31
+ **Observations:**
32
+ **Decisions made without stopping:**
33
+
34
+ ### P0-G1 — PENDING
35
+ **Verify output:**
36
+ **Observations:**
37
+
@@ -0,0 +1,75 @@
1
+ # {{PROJECT_NAME}} — Execution Guide
2
+
3
+ > **You are the Executor.** The Auditor wrote this file and will re-run every gate
4
+ > independently. Read `plan-of-record.md` once for context, then work only from here.
5
+ > Report every task in `compliance-log.md`.
6
+
7
+ ---
8
+
9
+ ## Rules of engagement
10
+
11
+ 1. **One task at a time, in order.** No batching. Do not start a phase whose
12
+ predecessor is not marked `APPROVED` in the compliance log.
13
+ 2. **Never invent a value the codebase declares.** Read it. Needing to ask for one
14
+ means a file was skipped.
15
+ 3. **Never guess a cause. Observe it.** Read the log, run the query, print the value.
16
+ 4. **Verification is running the thing, not reading the code.** "I reviewed it and it
17
+ looks correct" is reported as `FAILED`.
18
+ 5. **Scope is the task text.** Unrelated problems go in *Observations*. Do not fix
19
+ them.
20
+ 6. **Stop and ask** when this document contradicts the code, when a task needs a
21
+ decision this document does not make, or when a previously passing check starts
22
+ failing for reasons unrelated to your change. If you resolve an ambiguity without
23
+ stopping, log the decision. A decision in the plan of record is settled; a factual
24
+ claim never is — if this document states something the code contradicts, the
25
+ evidence outranks the order.
26
+ 7. **When the system cannot do what a task asks, that is the deliverable.** Report it
27
+ and stop. A task that ends in a well-argued finding is a success.
28
+ 8. Project-specific rules that apply to every task — list them here, cited from their
29
+ source rather than restated:
30
+ -
31
+ -
32
+
33
+ ## Reporting format
34
+
35
+ For each task, append to `compliance-log.md`:
36
+
37
+ ```
38
+ ### <TASK-ID> — DONE | BLOCKED | FAILED
39
+ **Changed:** <paths>
40
+ **Verify output:**
41
+ <pasted, literal, unedited command output>
42
+ **Observations:** <or "none">
43
+ **Decisions made without stopping:** <or "none">
44
+ ```
45
+
46
+ A `DONE` with no pasted output is recorded as `FAILED`.
47
+
48
+ ---
49
+
50
+ # Phase 0 — <name>
51
+
52
+ ### P0-T1 — <imperative, one line>
53
+
54
+ **Goal:**
55
+ **Files:**
56
+ **Steps:**
57
+ 1.
58
+
59
+ **Expected failure to avoid:**
60
+
61
+ **Verify:**
62
+ ```bash
63
+ ```
64
+
65
+ **Report:** `P0-T1`
66
+
67
+ ---
68
+
69
+ ### P0-G1 — Gate: <claim under test>
70
+
71
+ **Proven by:** <the check that proves the claim>
72
+
73
+ **Negative control:** <how you remove the protection, which check fails, and that it passes again once restored>
74
+
75
+ **Report:** `P0-G1`
@@ -0,0 +1,79 @@
1
+ # {{PROJECT_NAME}} — Plan of Record
2
+
3
+ > **Status:** draft. This document holds the *what* and the *why*. Nobody implements
4
+ > from this file. The executable instructions live in `execution-guide.md`; evidence
5
+ > goes in `compliance-log.md`.
6
+
7
+ **Target version / milestone:**
8
+ **Operating mode:** <Guided | Autonomous>
9
+
10
+ ---
11
+
12
+ ## 1. Why this exists (opportunity framing)
13
+
14
+ What problem is this solving, and why now. If several requests trace back to one
15
+ underlying gap, name the gap here rather than listing the requests as unrelated.
16
+
17
+ - **Target outcome:** <measurable behavior, metric, or system state that changes when this is done>
18
+ - **Problem / friction:** <verified gap or failure mode in the current system, without prescribing the feature yet>
19
+ - **Cost of doing nothing:** <concrete impact of not doing this work or deferring it>
20
+
21
+ ## 2. What the audit of the current system found
22
+
23
+ | Finding | Evidence |
24
+ |---|---|
25
+ | | |
26
+
27
+ State each finding with the command or artifact that established it, not from memory.
28
+
29
+ ## 3. Opportunity shaping & decisions (settled — reopening one is a stop, not a choice)
30
+
31
+ For open-design or new-capability work, compare at least three distinct approaches before
32
+ locking the architecture. For deterministic bugfixes, security patches, schema migrations,
33
+ or strict compliance work, mark the shaping and assumption fields as
34
+ `N/A (Deterministic Fix/Compliance)` and go straight to `D1`.
35
+
36
+ - **Option A (minimal / existing tooling / config-only):** <approach, cost, and limits — or `N/A (Deterministic Fix/Compliance)`>
37
+ - **Option B (balanced / pragmatic implementation):** <approach, cost, and limits — or `N/A (Deterministic Fix/Compliance)`>
38
+ - **Option C (full architectural / custom build):** <approach, cost, and limits — or `N/A (Deterministic Fix/Compliance)`>
39
+ - **Selected option & rationale:** <which option wins and why the other two were rejected — or `N/A (Deterministic Fix/Compliance)`>
40
+ - **Riskiest assumption & first-phase validation:** <the primary value, usability, feasibility, or viability assumption that could invalidate the plan, and how the first phase (`P0` or `P1`) tests it before building the rest — or `N/A (Deterministic Fix/Compliance)`>
41
+
42
+ ### D1 — <decision name>
43
+
44
+ What was decided, what alternative was rejected and why, what failure this prevents.
45
+
46
+ ## 4. What this deliberately does not do
47
+
48
+ Scope boundaries the Auditor is holding, so an Executor (or a future Auditor) doesn't
49
+ drift into rebuilding something that was cut on purpose.
50
+
51
+ - **Explicit non-goals:** <what is deliberately out of scope for this run>
52
+
53
+ ## 5. Phases
54
+
55
+ When the plan carries an unverified technical or product assumption, the first phase
56
+ (`P0` or `P1`) must test that riskiest assumption before building secondary scaffolding.
57
+
58
+ | Phase | Delivers | Risk |
59
+ |---|---|---|
60
+ | | | |
61
+
62
+ ## 6. Deferred items ledger
63
+
64
+ | ID | What | Deferred to | Closed by |
65
+ |---|---|---|---|
66
+ | | | | |
67
+
68
+ Every decision or annex that pushes work to a future phase gets a row here in the same
69
+ edit. An open row (`Closed by` without a task ID) for a phase being closed is a stop.
70
+
71
+ ## 7. Request traceability
72
+
73
+ | Origin request | Where it lands |
74
+ |---|---|
75
+ | | |
76
+
77
+ ## 8. Standards this work is held to
78
+
79
+ Cite the project's own conventions rather than restating them here.