harness-everything 0.38.0 → 0.39.0

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.
Files changed (62) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/AGENTS.md +79 -63
  4. package/CHANGELOG.md +25 -0
  5. package/benchmarks/results/reviews/pr353-r6-2026-10-22/README.md +76 -0
  6. package/benchmarks/results/reviews/pr353-r6-2026-10-22/a-reviews-b.md +191 -0
  7. package/benchmarks/results/reviews/pr353-r6-2026-10-22/b-reviews-a.md +100 -0
  8. package/benchmarks/results/reviews/pr353-r6-2026-10-22/baseline-probes.log +47 -0
  9. package/benchmarks/results/reviews/pr353-r6-2026-10-22/bom-red.log +85 -0
  10. package/benchmarks/results/reviews/pr353-r6-2026-10-22/bom-transition.txt +25 -0
  11. package/benchmarks/results/reviews/pr353-r6-2026-10-22/coordinator-probes.txt +84 -0
  12. package/benchmarks/results/reviews/pr353-r6-2026-10-22/cross-suite.txt +18 -0
  13. package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-bom.log +3 -0
  14. package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-consistency.log.gz +0 -0
  15. package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-core.log +198 -0
  16. package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-probes.log +27 -0
  17. package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-producer.log +83 -0
  18. package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-review.md +89 -0
  19. package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-transitions.log +5 -0
  20. package/benchmarks/results/reviews/pr353-r6-2026-10-22/implementation-a.md +166 -0
  21. package/benchmarks/results/reviews/pr353-r6-2026-10-22/implementation-b.md +264 -0
  22. package/benchmarks/results/reviews/pr353-r6-2026-10-22/logs.sha256 +15 -0
  23. package/benchmarks/results/reviews/pr353-r6-2026-10-22/peer-a-probe.log +62 -0
  24. package/benchmarks/results/reviews/pr353-r6-2026-10-22/peer-a-probe.txt +313 -0
  25. package/benchmarks/results/reviews/pr353-r6-2026-10-22/peer-b-probe.log +51 -0
  26. package/benchmarks/results/reviews/pr353-r6-2026-10-22/peer-b-probe.txt +94 -0
  27. package/benchmarks/results/reviews/pr353-r6-2026-10-22/semantic-transitions.txt +25 -0
  28. package/benchmarks/results/reviews/pr353-r6-2026-10-22/source.sha256 +9 -0
  29. package/benchmarks/results/reviews/pr353-r6-2026-10-22/tests-a-on-b-core.log +201 -0
  30. package/benchmarks/results/reviews/pr353-r6-2026-10-22/tests-a-on-b-producer.log +82 -0
  31. package/benchmarks/results/reviews/pr353-r6-2026-10-22/tests-b-on-a-core.log +197 -0
  32. package/benchmarks/results/reviews/pr353-r6-2026-10-22/tests-b-on-a-producer.log +82 -0
  33. package/benchmarks/results/reviews/pr353-r6-2026-10-22/verify-all.log.gz +0 -0
  34. package/benchmarks/results/reviews/pr353-r6-2026-10-22/verify-gate-summary.json +22 -0
  35. package/ci/fixtures/doc-obligations/reconciliation-s2a/harness.js +489 -0
  36. package/ci/fixtures/doc-obligations/reconciliation-s2a/vectors.json +617 -0
  37. package/ci/mechanism-325-3b-s2a-core.test.js +840 -0
  38. package/ci/mechanism-325-3b-s2a-producer.test.js +564 -0
  39. package/docs/doc-workflow-reconciliation.md +357 -0
  40. package/harness-everything/SKILL.md +1 -1
  41. package/harness-everything/scripts/project-docs-resolver.js +42 -8
  42. package/hooks/scripts/lib/doc-reconciliation-core.js +280 -0
  43. package/hooks/scripts/lib/doc-reconciliation-events.js +141 -0
  44. package/hooks/scripts/lib/doc-reconciliation-producer.js +206 -0
  45. package/multi-agent-workspace/SKILL.md +1 -1
  46. package/multi-agent-workspace/scripts/project-docs-resolver.js +42 -8
  47. package/opencode-plugin/plugin.json +1 -1
  48. package/package.json +1 -1
  49. package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
  50. package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-core.js +280 -0
  51. package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-events.js +141 -0
  52. package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-producer.js +206 -0
  53. package/plugins/harness-everything/plugin.json +1 -1
  54. package/plugins/harness-everything/skills/harness-everything/SKILL.md +1 -1
  55. package/plugins/harness-everything/skills/harness-everything/scripts/project-docs-resolver.js +42 -8
  56. package/plugins/harness-everything/skills/multi-agent-workspace/SKILL.md +1 -1
  57. package/plugins/harness-everything/skills/multi-agent-workspace/scripts/project-docs-resolver.js +42 -8
  58. package/plugins/harness-everything/skills/to-spec/SKILL.md +1 -1
  59. package/plugins/harness-everything/skills/to-spec/scripts/project-docs-resolver.js +42 -8
  60. package/sbom.cdx.json +7 -7
  61. package/to-spec/SKILL.md +1 -1
  62. package/to-spec/scripts/project-docs-resolver.js +42 -8
@@ -10,7 +10,7 @@
10
10
  "name": "harness-everything",
11
11
  "source": "./",
12
12
  "description": "Harness OS: an orchestrated agent operating system — tier routing, circuit breaker guardrails, verification gates, WAL session memory, and self-evolving workspace rules.",
13
- "version": "0.38.0",
13
+ "version": "0.39.0",
14
14
  "author": {
15
15
  "name": "Miya Daniel"
16
16
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "harness-everything",
3
3
  "description": "Harness OS: an orchestrated agent operating system — tier routing, circuit breaker guardrails, verification gates, WAL session memory, and self-evolving workspace rules.",
4
- "version": "0.38.0",
4
+ "version": "0.39.0",
5
5
  "author": {
6
6
  "name": "Miya Daniel"
7
7
  },
package/AGENTS.md CHANGED
@@ -1,93 +1,109 @@
1
1
  ---
2
- description: Operating guide for AI agents working inside the Harness-everything repository — layout, change rules, quality gates, and release policy.
2
+ description: Operating guide for AI agents working inside the Harness-everything repository — how we work, layout, change rules, quality gates, and release policy.
3
3
  ---
4
4
 
5
5
  # AGENTS.md — Working in This Repository
6
6
 
7
- You are modifying **Harness**: an orchestrated agent operating system (skills + hooks/plugins + routing) for AI coding agents. Changes here ship to real agent sessions; a vague `SKILL.md`, stale manifest, contradictory platform claim, or selected workflow that remains bypassable can misroute other people's agents. Precision is the product.
7
+ You are modifying **Harness**: an orchestrated agent operating system (skills + hooks/plugins + routing) for AI coding agents. Changes here ship to real agent sessions. A vague `SKILL.md`, a stale manifest, a contradictory platform claim or a bypassable selected workflow can misroute other people's agents. Precision is the product.
8
+
9
+ ## How We Work
10
+
11
+ Harness exists to put agents on the **fastest path to a working result**, not to fence them in. Prefer mechanisms that make the right action the easy one over written demands that agents talk themselves out of.
12
+
13
+ ```mermaid
14
+ flowchart LR
15
+ A["1. Wire the whole path<br/>(smallest end-to-end version)"] --> B["2. Record a baseline<br/>on that path"]
16
+ B --> C["3. Improve one thing per stage,<br/>compare to the baseline"]
17
+ C --> D["4. Lock behaviour<br/>with tests against drift"]
18
+ C -. "effect not measurable<br/>on the full path" .-> A
19
+ ```
20
+
21
+ - **Whole path first.** Do not polish details or add tests for parts that are not connected yet.
22
+ - **Stages follow the full path.** A stage whose effect cannot be measured end to end is split wrongly.
23
+ - **Mechanisms over mandates.** Put recurring rules in CI, hooks, mods or templates so actions match them naturally. A new prose MUST is the last resort.
24
+ - **Dogfood the rules.** Docs, packets and reports written here follow the same doc rules Harness ships.
25
+ - **Coordinator role.** In multi-agent work the coordinator dispatches and analyses. Agents and the reviewer check each step; the coordinator re-verifies everything at the final stage.
26
+
27
+ ### Writing docs (this file included)
28
+
29
+ 1. **Mermaid** for anything that can be drawn: flows, stages, dependencies, state.
30
+ 2. **Short bullets or tables** for rules and facts.
31
+ 3. **Prose** only for detail that needs it; link it rather than inline it.
8
32
 
9
33
  ## Repository Layout
10
34
 
11
35
  | Path | What it is |
12
36
  |---|---|
13
37
  | `<skill-name>/SKILL.md` | One canonical skill per top-level directory. Frontmatter: `name`, `description`, `metadata.author`, `metadata.version`. |
14
- | `hooks/` | Claude Code lifecycle hook scripts and shared mechanisms such as circuit breaker, workflow/action/scope guards, and stop gates. Do not infer that every host packages every hook. |
38
+ | `hooks/` | Claude Code lifecycle hooks and shared mechanisms (circuit breaker, workflow/action/scope guards, stop gates). Not every host packages every hook. |
15
39
  | `harness-everything/scripts/` | Runtime: kernel/tier routing, workflow contract, verification, bootstrap, self-heal. |
16
- | `opencode-plugin/` | OpenCode native plugin implementation. Mechanism-tested, with partial live-host evidence for project-scope `.js` loading and edit/verification state on OpenCode 1.18.31 (macOS); see the evidence boundary below. |
40
+ | `opencode-plugin/` | OpenCode native plugin. Mechanism-tested, with partial live-host evidence (see the boundary below). |
17
41
  | `.agents/plugins/` + `plugins/harness-everything/` | Local OpenAI/Codex marketplace + `.codex-plugin` package with canonical skill copies and packaged session/prompt hooks. |
18
42
  | `submission/openai/` | Public OpenAI Skills-only listing/test inputs. The public artifact does not include local `.codex-plugin` lifecycle hooks. |
19
43
  | `evals/<skill>/` | Trigger/routing eval per skill (waza format). Required for every canonical routed skill. |
20
- | `behavioral-evals/` | LLM-behavior cases run via headless CLI sessions and structurally validated by CI. |
44
+ | `behavioral-evals/` | LLM-behavior cases run via headless CLI sessions, structurally validated by CI. |
21
45
  | `benchmarks/` | BENCHMARK_SOP fixtures and recorded results. Evidence lives here or nowhere. |
22
- | `.claude-plugin/` | Claude Code plugin distribution manifests. Must list exactly the on-disk canonical skills. |
23
- | `docs/platform-capabilities.md` | Canonical current platform/install/enforcement/evidence matrix. |
24
- | `docs/repository-contract.md` | Generated current-state Node/workflow/action/gate contract. Regenerate with `npm run docs:sync`; do not hand-edit. |
25
- | `.nvmrc` | Primary development/CI Node runtime. `package.json#engines.node` remains the minimum supported runtime. |
26
- | `docs/`, `references/` | Philosophy, architecture, workflow documentation, shared checklists. |
46
+ | `.claude-plugin/` | Claude Code plugin manifests. Must list exactly the on-disk canonical skills. |
47
+ | `docs/platform-capabilities.md` | Canonical platform/install/enforcement/evidence matrix. |
48
+ | `docs/repository-contract.md` | Generated Node/workflow/action/gate contract. Regenerate with `npm run docs:sync`; never hand-edit. |
49
+ | `.nvmrc` | Primary dev/CI Node runtime. `package.json#engines.node` stays the supported minimum. |
50
+ | `docs/`, `references/` | Philosophy, architecture, workflow docs, shared checklists. |
27
51
 
28
52
  ## OpenCode evidence boundary
29
53
 
30
- The retained [OpenCode evidence](benchmarks/results/live-host/opencode-2026-09-16/README.md) supports project-scope `.js` loading and edit/verification state on OpenCode 1.18.31 (macOS). The final snapshot is post-reset (`hardLock: false`, `count: 1`). Hard lock is only an interactive observation with no retained blocked-tool trace; reflection was operator-seeded, then agent-rewritten. Agent-controlled state deletion resets the breaker. Global scope, npm-package installation, and other OpenCode versions remain unverified.
31
-
32
- ## Non-Negotiable Change Rules
33
-
34
- 1. **Every canonical SKILL.md keeps ≤ 500 tokens** (hard CI gate) and must contain `## USE FOR:` and `## DO NOT USE FOR:`. Deep detail goes in references/guides.
35
- 2. **Descriptions are routing surfaces.** Differentiate neighboring skills deliberately; `test:collision` guards overlap.
36
- 3. **A new canonical skill ships with a routing eval.** Positive task `description:` must exactly match the skill frontmatter description.
37
- 4. **Release version policy:** normal PRs do not manually bump package/plugin versions. `semantic-release` owns stable SemVer and `scripts/sync-release-version.js` owns distribution synchronization. Nested sub-skills inherit their parent skill version.
38
- 5. **Distribution manifests are generated facts:** add/remove/rename changes must sync every copied/listed distribution. Run `npm run plugin:sync`, `npm run test:consistency`, and `npm run test:plugin:openai`.
39
- 6. **Platform capability claims are tested contracts.** Update `docs/platform-capabilities.md` with integration behavior changes. Package/mechanism evidence is not live-host evidence, and public Skills-only behavior does not include local lifecycle hooks.
40
- 7. **Runtime/workflow claims are generated facts.** `package.json`, `.nvmrc`, Dockerfile, and active workflows feed `scripts/repository-contract.js`; run `npm run docs:sync` after relevant changes.
41
- 8. **CHANGELOG.md keeps pending human-authored notes under `[Unreleased]`.** Semantic-release owns stable headings/tags/release notes.
42
- 9. **Conventional Commit type is release input.** Breaking→major; `feat`→minor; `fix`/`perf`/`refactor`/`build`/`revert`→patch; docs/test/ci/style/chore do not release by themselves.
43
- 10. **Selected workflow is a semantic contract; tactics remain flexible.** Compose ordered requirement steps with declared required/optional skill or reference bindings. Load/resolve bindings only when their step (or dependency-ready Fable stage) is active; required bindings MUST resolve before that step passes, and applicable skill core contracts MUST be followed. Unknown/unavailable bindings stay visible and unresolved. Selected-topology obligations MUST resolve; missing host evidence may produce reminders, not a persistent Harness lock.
44
- 11. **User-visible Harness Status is mandatory for non-trivial work.** Render one readable Markdown block headed `### 🚦 Harness Status`, with bullet-aligned bold `Current`, `Read / Evidence`, `Next`, plus optional `Risk / Blocked`; use nested evidence bullets when useful. Emit it before substantive execution, after major phases, on direction changes, during long work at meaningful boundaries, and before final completion. The routing checkpoint is internal source state, not a second user-facing block. This semantic MUST does not create a hard lock.
45
- 12. **Tier-3/Fable isolation disposition is mandatory before broad mutation.** Use/reuse a verified linked Git worktree, or record an explicit degraded fallback when isolation is unavailable or the user explicitly chooses to stay in place. Ordinary isolation SHOULD be used when it materially reduces collision/risk. Failure to isolate is a visible semantic gap, not a Harness-owned deadlock. See [workflow-runtime.md](docs/workflow-runtime.md).
46
- 13. **Use contract strength deliberately.** MUST = required semantic obligation; SHOULD = expected default with an evidence-based exception; MAY = optional optimization. Do not use recommend/prefer/advisory/guidance to weaken a MUST. See [philosophy.md](docs/philosophy.md#contract-strength-must--should--may).
47
- 14. **The turn label line is mandatory on every turn, trivial ones included.** End the final message of every turn — short answers, lookups, questions back to the user — with one hidden `<!-- harness-label {...} -->` line: your own post-work judgement of validity, context dependence, tier, intents, workflow and skills used ([docs/routing.md](docs/routing.md#turn-label-line)). It records data and never gates routing.
54
+ The retained [OpenCode evidence](benchmarks/results/live-host/opencode-2026-09-16/README.md) supports project-scope `.js` loading and edit/verification state on OpenCode 1.18.31 (macOS).
48
55
 
49
- ## Verification Before You Claim Done
56
+ - The final snapshot is post-reset (`hardLock: false`, `count: 1`).
57
+ - Hard lock is only an interactive observation with no retained blocked-tool trace.
58
+ - Reflection was operator-seeded, then agent-rewritten. Agent-controlled state deletion resets the breaker.
59
+ - Global scope, npm-package installation, and other OpenCode versions remain unverified.
50
60
 
51
- Run the gates that cover the same contract categories as CI:
52
-
53
- ```bash
54
- npm test
55
- npm run test:mutations
56
- npm run test:mechanism
57
- npm run test:consistency
58
- npm run test:repo-contract
59
- npm run test:docs:capabilities
60
- npm run test:references
61
- npm run test:release
62
- npm run test:collision
63
- npm run test:routing:skills
64
- npm run test:routing:invariants
65
- npm run test:plugin:openai
66
- npm run test:plugin:submission
67
- npm run test:platform:compatibility
68
- npm run test:portability
69
- ```
61
+ ## Change Rules
70
62
 
71
- `npm run verify:all` runs this set in CI order and prints paste-ready evidence; every known gate stays in the report as PASS/FAIL/UNCHECKED with a reason. `-- --fast` runs the pre-push subset, `-- --clean` runs every gate in a fresh detached worktree of HEAD, and `-- --node22` adds the Node.js 22 execution smoke-test lane (Node 22 dependency-install compatibility stays UNCHECKED locally; CI's runtime-floor job owns it).
63
+ **Skills and routing**
72
64
 
73
- If waza is installed (`~/bin/waza`), also run:
65
+ 1. **Every canonical SKILL.md keeps ≤ 500 tokens** (CI gate) and contains `## USE FOR:` and `## DO NOT USE FOR:`. Detail goes in references/guides.
66
+ 2. **Descriptions are routing surfaces.** Differentiate neighbouring skills deliberately; `test:collision` guards overlap.
67
+ 3. **A new canonical skill ships with a routing eval.** The positive task `description:` exactly matches the skill frontmatter description.
74
68
 
75
- ```bash
76
- waza check <skill-dir>
77
- waza spec verify <skill> evals/<skill>/eval.yaml --fail --threshold 1
78
- waza tokens check
79
- ```
69
+ **Release and distribution**
80
70
 
81
- Node.js 24 is primary CI across Ubuntu/Windows/macOS; a Node.js 22 lane protects the supported minimum. See [docs/repository-contract.md](docs/repository-contract.md).
71
+ 4. **Versions:** normal PRs never bump versions. `semantic-release` owns SemVer; `scripts/sync-release-version.js` syncs distributions. Nested sub-skills inherit their parent's version.
72
+ 5. **Distribution manifests are generated facts.** After add/remove/rename run `npm run plugin:sync`, `npm run test:consistency` and `npm run test:plugin:openai`.
73
+ 6. **Platform capability claims are tested contracts.** Update `docs/platform-capabilities.md` with integration changes. Package/mechanism evidence is not live-host evidence; public Skills-only behavior has no local lifecycle hooks.
74
+ 7. **Runtime/workflow claims are generated facts.** `package.json`, `.nvmrc`, Dockerfile and active workflows feed `scripts/repository-contract.js`; run `npm run docs:sync` after relevant changes.
75
+ 8. **CHANGELOG.md:** human notes go under `[Unreleased]`; semantic-release owns stable headings, tags and release notes.
76
+ 9. **Conventional Commit type is release input:** breaking→major, `feat`→minor, `fix`/`perf`/`refactor`/`build`/`revert`→patch; docs/test/ci/style/chore do not release alone.
82
77
 
83
- Do not report "it works" from code reading. State the evidence layer proved: package, deterministic mechanism, live host, or behavior.
78
+ **Workflow behaviour**
84
79
 
85
- ## Behavioral & Benchmark Evidence
80
+ 10. **Selected workflow is a semantic contract; tactics remain flexible.** Compose ordered requirement steps with declared required/optional skill or reference bindings. Resolve a binding only when its step (or dependency-ready Fable stage) is active; required bindings MUST resolve before that step passes, and applicable skill core contracts MUST be followed. Unknown/unavailable bindings stay visible. Selected-topology obligations MUST resolve; missing host evidence yields reminders, not a persistent Harness lock.
81
+ 11. **User-visible Harness Status is mandatory for non-trivial work.** One Markdown block headed `### 🚦 Harness Status` with bold `Current`, `Read / Evidence`, `Next`, optional `Risk / Blocked`; use nested evidence bullets when useful. Emit it before substantive execution, after major phases, on direction changes, at long-run boundaries and before completion. The routing checkpoint is internal state, not a second block. Not a hard lock.
82
+ 12. **Tier-3/Fable isolation disposition is mandatory before broad mutation.** Use a verified linked Git worktree, or record an explicit degraded fallback when isolation is unavailable or the user chooses to stay in place. Ordinary isolation SHOULD be used when it materially reduces collision risk. Failure to isolate is a visible gap, not a Harness deadlock. See [workflow-runtime.md](docs/workflow-runtime.md).
83
+ 13. **Use contract strength deliberately** ([philosophy.md](docs/philosophy.md#contract-strength-must--should--may)): MUST = required semantic obligation, SHOULD = default with an evidence-based exception, MAY = optional. Do not use recommend/prefer/advisory/guidance to weaken a MUST.
84
+ 14. **The turn label line is mandatory on every turn, trivial ones included.** End each turn's final message with one hidden `<!-- harness-label {...} -->` line giving your post-work judgement ([docs/routing.md](docs/routing.md#turn-label-line)). It records data and never gates routing.
86
85
 
87
- Deterministic mechanism tests prove the tested hook/plugin contract; they do **not** prove a real host loaded it or that behavior improved. For behavior:
86
+ ## Verification Before You Claim Done
87
+
88
+ ```mermaid
89
+ flowchart LR
90
+ F["npm run verify:all -- --fast<br/>(pre-push subset)"] --> V["npm run verify:all<br/>(CI order, PASS/FAIL/UNCHECKED report)"]
91
+ V -. optional .-> C["-- --clean<br/>(fresh worktree of HEAD)"]
92
+ V -. optional .-> N["-- --node22<br/>(Node 22 smoke lane)"]
93
+ ```
88
94
 
89
- - `node behavioral-evals/run.js run --engine opencode` (or `--engine claude`) — on-demand, token-costing.
90
- - Weekly behavioral workflow validates case structure and runs live cases only when its runner has the required CLI.
91
- - `node benchmarks/run.js scaffold <scenario>` → run both variants → `record` with evidence logs.
95
+ - `npm run verify:all` runs every CI gate category and prints paste-ready evidence. Individual gates: `npm test`, `npm run test:mutations`, `test:mechanism`, `test:consistency`, `test:repo-contract`, `test:docs:capabilities`, `test:references`, `test:release`, `test:collision`, `test:routing:skills`, `test:routing:invariants`, `test:plugin:openai`, `test:plugin:submission`, `test:platform:compatibility`, `test:portability`.
96
+ - With waza (`~/bin/waza`): `waza check <skill-dir>`, `waza spec verify <skill> evals/<skill>/eval.yaml --fail --threshold 1`, `waza tokens check`.
97
+ - CI runs Node.js 24 on Ubuntu/Windows/macOS plus a Node.js 22 floor lane ([repository-contract.md](docs/repository-contract.md)). Node 22 install compatibility stays UNCHECKED locally.
98
+ - Never report "it works" from code reading. Name the evidence layer: package, deterministic mechanism, live host or behavior.
99
+
100
+ ## Behavioral & Benchmark Evidence
101
+
102
+ | Claim | Evidence required |
103
+ |---|---|
104
+ | Hook/plugin contract holds | Deterministic mechanism test |
105
+ | A real host loaded and fired it | Preserved host/session artifact |
106
+ | Behavior improved | Paired evidence per #71 (baseline vs treatment) |
92
107
 
93
- For a live-host enforcement claim, preserve a host/session artifact showing the mechanism loaded and fired. For an effectiveness claim, use the paired evidence discipline in #71 rather than inferring improvement from mechanism presence.
108
+ - Behavior runs: `node behavioral-evals/run.js run --engine opencode` (or `--engine claude`). On demand; costs tokens. The weekly workflow validates structure and runs live cases only where the CLI exists.
109
+ - Benchmarks: `node benchmarks/run.js scaffold <scenario>`, run both variants, then `record` with evidence logs.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## [0.39.0](https://github.com/dyphn1/Harness-everything/compare/v0.38.0...v0.39.0) (2026-10-21)
6
+
7
+ ### Features
8
+
9
+ * **doc-lifecycle:** add s2a document evidence producer and reconciliation core ([#325](https://github.com/dyphn1/Harness-everything/issues/325)) ([7d54802](https://github.com/dyphn1/Harness-everything/commit/7d5480292891f4cbac126bfa4ed6dc43be9173f2))
10
+
11
+ ### Bug Fixes
12
+
13
+ * **doc-lifecycle:** bind captured origin pin to the s2a baseline ([#353](https://github.com/dyphn1/Harness-everything/issues/353)) ([59421f4](https://github.com/dyphn1/Harness-everything/commit/59421f41a8ce2b00250c96634a4a43ae0ba782bf))
14
+ * **doc-lifecycle:** bind s2a start pin, scope progress keys, stop should/n/a gating ([#325](https://github.com/dyphn1/Harness-everything/issues/325)) ([5e48a91](https://github.com/dyphn1/Harness-everything/commit/5e48a9119b511d60c23cccdbd06ca3f865d82d83))
15
+ * **doc-lifecycle:** make the s2a producer inventory portable to windows ([#325](https://github.com/dyphn1/Harness-everything/issues/325)) ([f1a9fb5](https://github.com/dyphn1/Harness-everything/commit/f1a9fb50e055e9ce21782d1ede96b926f08ff486))
16
+ * **doc-lifecycle:** reconcile s2a origin identity and binary records ([#353](https://github.com/dyphn1/Harness-everything/issues/353)) ([475fcfc](https://github.com/dyphn1/Harness-everything/commit/475fcfc26cf4c16a6ed5af40bc55c09281fe98c0))
17
+ * **doc-lifecycle:** reject prototype-sensitive s2a inventory ([#353](https://github.com/dyphn1/Harness-everything/issues/353)) ([b2b93ea](https://github.com/dyphn1/Harness-everything/commit/b2b93ea3d52ab9316d679b323343b5abe0525ccd))
18
+ * **doc-lifecycle:** resolve s2a workspace identity with native realpath on windows ([#325](https://github.com/dyphn1/Harness-everything/issues/325)) ([c663fd8](https://github.com/dyphn1/Harness-everything/commit/c663fd8479869d6a3c7930bd47a067d4323cb6c9)), closes [#353](https://github.com/dyphn1/Harness-everything/issues/353)
19
+ * **doc-lifecycle:** revalidate the s2a start pin at event acceptance ([#325](https://github.com/dyphn1/Harness-everything/issues/325)) ([2cf466d](https://github.com/dyphn1/Harness-everything/commit/2cf466d04e52dd92f8df2b7263348287f9eef2da))
20
+
5
21
  ## [0.38.0](https://github.com/dyphn1/Harness-everything/compare/v0.37.0...v0.38.0) (2026-10-21)
6
22
 
7
23
  ### Features
@@ -16,6 +32,15 @@ All notable changes to this project are documented in this file.
16
32
 
17
33
  ## [Unreleased]
18
34
 
35
+ - Reject root-level `__proto__` files in S2a snapshot capture and validation instead of silently dropping their document obligations (#353).
36
+
37
+ - Bind the S2a captured origin identity to the snapshot identity (workspace, session, workflow, revision, task), the captured plan and the selected active host, so a jointly substituted origin context and provider context cannot earn credit in either reconciliation mode; bind the captured config bytes to the captured inventory (#353).
38
+
39
+ - Keep a whole-project S2a inventory usable when it contains binary records: every stored byte stays in the candidate digest, records the derive contract cannot observe are omitted from semantic derivation, and governed/derived/code/test records that cannot be decoded fail closed as inventory-unsupported (#353).
40
+
41
+ - Reject S2a document evidence when the captured origin commit disagrees with the hashed baseline, including joint provider/context commit replacement; also reject inconsistent roots within the snapshot (#353).
42
+
43
+ - Ship the unwired S2a document evidence producer and reconciliation core (snapshot capture, captured config, accepted-origin adapter, expected-set reconciliation); S1 stays no-credit until S2b host integration.
19
44
  - Ship default-OFF Phase 3b S1 scope assessment and no-credit runtime gate (opt in with `HARNESS_DOC_RECONCILIATION_PILOT=1`); S2 pending (S3 shipped in 0.37.0), E1 not started.
20
45
 
21
46
  ## [0.37.0](https://github.com/dyphn1/Harness-everything/compare/v0.36.4...v0.37.0) (2026-10-21)
@@ -0,0 +1,76 @@
1
+ # PR #353 — two independent implementations and cross-validation
2
+
3
+ - Base: `59421f41a8ce2b00250c96634a4a43ae0ba782bf`.
4
+ - Environment: macOS, Node 24.14.1; per-worktree temporary directories.
5
+ - Selected: **A plus the coordinator's BOM fix**. Both OpenCode reviewers accept A; B accepts the final delta.
6
+ - Scope: S2a only. No runtime wiring, public derive/checker API, digest schema, version or dependency change.
7
+ - Evidence layer: **deterministic mechanism**, with fake origin providers; no host provenance or live-host claim.
8
+
9
+ ```mermaid
10
+ flowchart LR
11
+ Base["59421f4"] --> A["OpenCode A: independent implementation"]
12
+ Base --> B["OpenCode B: independent implementation"]
13
+ A --> X["Swap tests + independent probes + peer reviews"]
14
+ B --> X
15
+ X --> S["Select A; add BOM regression and fix"]
16
+ S --> V["Full gates + final OpenCode review"]
17
+ ```
18
+
19
+ ## Requirements addressed
20
+
21
+ | Comment | Final behavior |
22
+ | --- | --- |
23
+ | P1: disconnected origin and event identity halves | Match all five origin-correlated identity fields, captured plan fields and selected active host; reject partial substitutions in verification, review and cached evidence. |
24
+ | P1 same-class config link | Captured config source bytes must match the captured candidate inventory. |
25
+ | P2: ordinary binary assets reject a complete capture | Keep all captured bytes in baseline/candidate hashes; omit undecodable data only outside the conservative document/code/test/derived/frontmatter relevance surface. Producer and core use one helper. |
26
+ | Coordinator's BOM defect | A leading UTF-8 BOM cannot conceal undecodable frontmatter from the relevance check. |
27
+
28
+ ## Comparison and selection (executed unless marked)
29
+
30
+ | Check | A | Revised B |
31
+ | --- | --- | --- |
32
+ | Own core / producer suites | 195/0; 76/0 | 193/0; 78/0 |
33
+ | Common coordinator probes | 26/0 | 26/0 |
34
+ | Candidate-content transition probes | 4/0 | 4/0 (initial B was 0/4; fixed before comparison) |
35
+ | BOM frontmatter probe | 0/2 | 0/2 |
36
+ | B's tests against A | 193/0 core; 78/0 producer | — |
37
+ | A's tests against B | — | 193/2 core; 74/2 producer |
38
+ | Peer assessment | accepted by B | A found plan/config links and masked-frontmatter gaps; not accepted as-is |
39
+
40
+ A closes more represented identity links and fails closed on ambiguous semantic inputs. Its relevance rule avoids extra derivation passes but mirrors existing path rules; this maintenance cost is stated in code with a `shortcut:` comment. The BOM gap was independently reproduced for both candidates, then fixed in the selected tree.
41
+
42
+ Peer reviews are [A reviews B](a-reviews-b.md) and [B reviews A](b-reviews-a.md). [Final integration review](final-review.md): **ACCEPT**, source-traced (no tests rerun by the reviewer).
43
+
44
+ ## Final evidence
45
+
46
+ | Check | Result |
47
+ | --- | --- |
48
+ | Baseline coordinator probes | 10 PASS / 16 FAIL |
49
+ | BOM regression before fix | 78 PASS / 2 FAIL / 0 INFRA |
50
+ | Final core | **195 PASS / 0 FAIL / 0 INFRA** |
51
+ | Final producer | **80 PASS / 0 FAIL / 0 INFRA** |
52
+ | Final independent probes | **26 + 4 + 2 = 32 PASS / 0 FAIL** |
53
+ | `npm run verify:all` | **13 PASS / 0 FAIL / 3 UNCHECKED** |
54
+ | `verify-gate.js --json` after cleanup | Discovered `package-test` ran with exit **0**; gate status `UNCHECKED_DISCOVERED` because no declared project verification contract exists (not a contract PASS). |
55
+ | Post-review comment/wording-only cleanup | consistency and diff whitespace PASS; no functional delta after full gates |
56
+
57
+ The three UNCHECKED entries are Node 22 execution/install lanes. CI owns the cross-platform and runtime-floor evidence. Focused stdout, swapped-suite logs, losslessly compressed full-gate logs and source hashes are retained beside this README. Probe scripts are retained as `.txt` evidence; they were run outside the repository and are not installed runtime code. Full OpenCode JSON streams remain local rather than being shipped.
58
+
59
+ ## Limits and follow-ups
60
+
61
+ - Undecodable files under code/test/governed/derived paths remain **unavailable by design**, including harmless binary test fixtures or diagrams under governed globs. This conservative acceptance boundary is explicit in the S2a contract; exploratory probes confirm B accepts a no-REQ test fixture while A refuses it. No claim that every binary file in every path is accepted.
62
+ - A mirrors the derive contract's code/test/glob rules. Keep them synchronized until a shared classifier is exposed.
63
+ - Malformed byte records may now report `inventory-unsupported` rather than the old `invalid-input`; both withhold credit. This is a non-blocking diagnostic drift noted by B.
64
+ - Fully self-consistent restatement of all detached metadata and cached accepted structures is outside S2a attestation: external origin authentication remains S2b. Both independent implementations share this boundary.
65
+ - The owner decides PR readiness, merge and release.
66
+
67
+ ## Trust-boundary review
68
+
69
+ | Threat | Check |
70
+ | --- | --- |
71
+ | Context spoofing / metadata tampering | Five tuple fields, plan/config/host and config bytes linked before credit. |
72
+ | Binary omission | Relevant undecodable inputs fail closed; byte hashes retain every captured file. |
73
+ | Invalid snapshot | No event adaptation or eligibility. |
74
+ | Secrets / injected execution | Targeted changed-source scan found no added secret literal or dynamic execution; no endpoint/auth/dependency added. |
75
+
76
+ STATUS: DONE
@@ -0,0 +1,191 @@
1
+ # PR #353 — Cross-review of peer leg B (reviewer: leg A)
2
+
3
+ Reviewed: peer worktree `/Users/daniel.chang/Desktop/Skills/Harness-everything/.worktrees/353-r6-b`
4
+ (base `59421f41a8ce2b00250c96634a4a43ae0ba782bf`), report `/tmp/harness-353-r6-b/REPORT.md`, and B's
5
+ working-tree diff against `59421f4`.
6
+ Method: read B's current source, its test and doc diffs; ran **one** independent probe
7
+ (`/tmp/harness-353-r6-a/probe/cross-review-probe.js`, scratch, outside both repositories) against **both**
8
+ worktrees; no suite was re-run, no implementation was edited, no git/gh write was issued, no full gate
9
+ was run. The probe builds its own Git fixture repositories, its own fake origin provider and its own
10
+ event builder; it depends on neither leg's fixture harness.
11
+
12
+ ## Verdict
13
+
14
+ | | Peer B | Leg A |
15
+ | --- | --- | --- |
16
+ | P1 origin tuple (`workspaceId`, `sessionId`, `workflowId`, `workflowRevision`, `taskId`) | closed | closed |
17
+ | P1 `activeHost` ↔ captured selected config | closed | closed |
18
+ | P1 captured plan ↔ identity | **open** (F1) | closed |
19
+ | P1 captured config bytes ↔ captured inventory | **open** (F2) | closed |
20
+ | P2 binary bytes stay in both digests | closed | closed |
21
+ | P2 irrelevant binary asset does not break the capture | closed | closed |
22
+ | P2 baseline/candidate/new/deleted relevance class | closed | closed |
23
+ | P2 relevance decided by the unchanged derivation (no rule duplication) | **yes** | no (F5) |
24
+ | P2 a record that opens a frontmatter block cannot vanish | not guaranteed (F4) | closed |
25
+
26
+ **Peer B is not accepted as-is.** One blocker-class finding (F1) and two recommended additions (F2, F4),
27
+ all in the packet's own P1/P2 scope and all reproducible with the probe. With the minimal delta
28
+ described below, I accept B. **Leg A has no blocker-class finding** in this review; its only weakness is
29
+ a maintenance coupling (F5), not a present trust gap.
30
+
31
+ ## Probe results (one probe, both worktrees)
32
+
33
+ | Probe case | Expected | A | B |
34
+ | --- | --- | --- | --- |
35
+ | `p1-control-eligible` | eligible | eligible | eligible |
36
+ | `p1-joint-origin-task-substitution` (the packet's named attack) | rejected | rejected | rejected |
37
+ | `p1-plan-only-substitution` | rejected | rejected (`identity-mismatch`) | **accepted (eligible)** |
38
+ | `p1-config-bytes-substitution` | rejected | rejected (`config-capture-mismatch`) | **accepted (eligible)** |
39
+ | `p1-fully-joint-self-consistent-substitution` | rejected | accepted (eligible) | accepted (eligible) |
40
+ | `p2-asset-irrelevant` | ready | ready | ready |
41
+ | `p2-governed-path-unchanged` | unavailable | unavailable | unavailable |
42
+ | `p2-role-frontmatter-asset` | unavailable | unavailable | unavailable |
43
+ | `p2-masked-frontmatter-asset` | unavailable | unavailable | **ready** |
44
+ | `p2-new-binary-governed-record` | unavailable | unavailable | unavailable |
45
+ | `p2-deleted-binary-governed-record` | unavailable | unavailable | unavailable |
46
+ | `p2-binary-bytes-covered-by-both-digests` | differ | differ | differ |
47
+ | `p2-producer-core-parity` | no errors | no errors | no errors |
48
+ | `p2-malformed-record-rejected` | `invalid-input` | `invalid-input` | `invalid-input` |
49
+
50
+ Probe definitions: *plan-only* = the captured plan names another workflow and `taskScopeDigest` is
51
+ recomputed correctly, the identity and the captured origin context keep the original tuple; *config-bytes* =
52
+ the captured config source bytes are replaced and every digest that names them is recomputed, and the
53
+ cached acceptance is restated; *fully joint* = the captured origin context, the identity, the captured plan,
54
+ the digests and the cached acceptance are restated together; *masked frontmatter* = the record's bytes open
55
+ a `---` block whose closing delimiter is separated from it by one invalid UTF-8 byte.
56
+
57
+ ## Findings
58
+
59
+ **F1 — executed — peer B — blocker-class (P1 scope): the captured plan is not bound to the identity.**
60
+ `validateSnapshot` checks `originContext` against `identity` and `activeHost` against the config capture,
61
+ but nothing compares the captured plan with the identity. `taskScopeDigest` binds the plan *content* to the
62
+ identity's digest field; it does not bind the plan's workflow triple / task id to the identity's. A
63
+ snapshot whose plan describes another workflow, with the digest correctly recomputed, verifies as
64
+ `eligible` (probe `p1-plan-only-substitution`). The packet asks to "inspect all represented tuple links,
65
+ not only two examples" and to check the plan "where represented"; the plan represents `workflowId`,
66
+ `workflowRevision`, `sessionId` and `taskId`, which the identity also represents. B's shipped doc text
67
+ ("The plan stays bound through `taskScopeDigest`") states more than the code enforces. Fix: compare
68
+ `taskSemantics.workflow.{workflowId,workflowRevision,sessionId}`, `taskSemantics.task.taskId`,
69
+ `taskSemantics.prdRoot` and `taskSemantics.configDigest` with the identity inside the existing
70
+ `validateSnapshot` (A: `originBound`, ~6 lines, pure, no I/O).
71
+
72
+ **F2 — executed — peer B — recommended (same class): the captured config bytes are not bound to the
73
+ captured inventory.** Replacing the captured config source bytes and recomputing every digest that names
74
+ them (`configDigest`, `identity.configDigest`, the plan's `configDigest`, `taskScopeDigest`) plus
75
+ restating the cached acceptance verifies as `eligible` (probe `p1-config-bytes-substitution`). The
76
+ producer already enforces exactly this rule at capture (its config-source loop compares the captured
77
+ source bytes with the candidate records); the core re-checks nothing, so the two halves of the capture
78
+ can describe different files. Fix: the producer's rule as a core check → `config-capture-mismatch`
79
+ (A: `configBytesBound`, ~8 lines).
80
+
81
+ **F3 — executed — shared by both legs — contract-bounded, not a defect of either: a fully joint,
82
+ self-consistent restatement is accepted.** Restating the captured origin context, the identity, the
83
+ captured plan, the digests and the cached acceptance together yields `eligible` under A and B
84
+ (probe `p1-fully-joint-self-consistent-substitution`). The snapshot is detached and self-authenticating;
85
+ the only external anchor is the origin provider, which `acceptDocEvents` consults on a fresh acceptance
86
+ and the pure core never re-reads. This matches the S2a contract's own boundary ("external worktree
87
+ authentication remains outside this S2a guarantee"; S2b recollects every tuple and accepted binding before
88
+ credit). Consequence for the selection: F1 and F2 are *partial* defenses — they reject partial
89
+ substitutions, not a full restatement. Both legs share that boundary, so it is not a differentiator.
90
+
91
+ **F4 — executed — divergence — peer B: a record that opens a frontmatter block can still be omitted.**
92
+ The lifecycle decides "is this a frontmatter document" by the first line being exactly `---`
93
+ (`harness-everything/scripts/doc-lifecycle.js`, `parseFrontmatter`). B's relevance decision is the
94
+ unchanged derivation applied to the *lossy* reading of the record; when the invalid byte sits inside the
95
+ frontmatter block, the lossy reading is unterminated, carries no role, and the record is omitted
96
+ (probe `p2-masked-frontmatter-asset`: B → ready, A → unavailable). A governed document with one stray
97
+ invalid byte in its frontmatter can therefore be dropped from the derivation, so `doc-lint` / `link-check`
98
+ would not fire where a tolerant reader would see a governed PRD. Exotic, but it is the one probed case
99
+ where the two legs differ on a trust-relevant outcome. Fix on B: fail closed when a record's first line is
100
+ exactly `---` — the lifecycle's own test, independent of the witnesses (~3 lines).
101
+
102
+ **F5 — source-traced — leg A (for balance): A mirrors the derive contract's path rules inside the
103
+ reconciliation module.** Because `doc-obligations.js` is outside the write-set, A duplicates
104
+ `CODE_EXTENSION`, `TEST_PATH` and the contract's glob semantics to decide relevance. The duplication is
105
+ currently exact (the probe shows A and B agreeing on 8 of 9 P2 cases), but a later change to the derive
106
+ contract's code/test/glob rules would silently make A *omit* a record the contract treats as relevant —
107
+ the dangerous direction — with no test failure. B has no such surface: its relevance decision is the
108
+ derivation's own. Removing A's coupling needs either a public export of the contract's classification
109
+ (out of this packet's scope) or B's witness approach.
110
+
111
+ **F6 — executed — shared residual: a binary record at a governed path makes the capture unavailable even
112
+ when unchanged.** Both legs fail closed for `docs/prd/diagram.png` (probe `p2-governed-path-unchanged`;
113
+ B via the addition witness, A via the path rule). This matches the S2a contract ("Unsupported
114
+ encodings ... that prevent faithful identity yield unavailable") and is conservative in both, but it means
115
+ a repository holding a binary diagram under `docs/prd/` can never be captured. Availability cost, not a
116
+ trust gap; identical in both legs.
117
+
118
+ **F7 — executed — shared: the new/deleted record identity class is closed in both.** A binary record that
119
+ exists on only one side of the capture fails closed in both legs (probes `p2-new-binary-governed-record`,
120
+ `p2-deleted-binary-governed-record`), and both agree with the coordinator's transition probe. B's
121
+ round-2 witnesses (actual / addition / deletion) close the candidate-only omission the coordinator found
122
+ in B's first implementation; A's path rules cover the same paths. Neither leg depends on a newline-only
123
+ modification to detect the transition.
124
+
125
+ **F8 — executed — shared: byte integrity, parity and malformed inputs.** Both legs keep the binary bytes
126
+ in `candidateDigest` *and* `baselineDigest` (probe `p2-binary-bytes-covered-by-both-digests`), the core's
127
+ re-derivation accepts the producer's snapshot with a binary asset in both (probe
128
+ `p2-producer-core-parity`), and a record whose stored bytes do not match its digest is refused with
129
+ `invalid-input` in both (probe `p2-malformed-record-rejected`).
130
+
131
+ **F9 — source-traced — scope, API and parity between the legs.** Both legs touch the same nine files
132
+ inside the packet's write-set, change no public derive/checker API, no identity/digest schema, no S1
133
+ runtime and no workflow wiring, add no new `.js` file to the repository, and leave
134
+ `doc-reconciliation-events.js` untouched — correct, because that module already compares the provider
135
+ context with the captured origin context and calls `validateSnapshot`, so it inherits the P1 binding. Both
136
+ cores stay pure (no file, process or network activity); B's extra derivation calls are pure computations.
137
+ B's packaged copies are byte-identical to its canonical files (sha256 verified); A's parity is asserted
138
+ by its own suite. B's doc text and CHANGELOG entries accurately describe B's behaviour except for the
139
+ plan-binding claim noted in F1.
140
+
141
+ **F10 — inconclusive.** The completeness of B's relevance witnesses is not provable for every byte
142
+ sequence (B's own report says so; F4 is the demonstrated instance). Live-host provenance is out of reach
143
+ in both legs (the origin provider is an explicit fake). Platform coverage is macOS-only in both; the
144
+ Windows lane and the Node 22 floor remain CI's.
145
+
146
+ ## Comparison of the two approaches
147
+
148
+ **Peer B — strengths.** The relevance decision is the *unchanged derivation's own*, so there is no
149
+ extension allowlist and no duplicated path rules to drift (the packet's "inspect existing derive/lifecycle
150
+ semantics to justify relevance" in its strongest form). The three witnesses (actual transition, addition,
151
+ deletion) directly answer the coordinator's class requirement, and B's round-2 fix is a real improvement
152
+ over a naive path-rule approach. Its P1 origin binding is exactly equivalent to A's for the five tuple
153
+ fields and the host. Its test set is larger and pins the semantic-binary regressions.
154
+
155
+ **Peer B — defects.** F1 (blocker-class, P1 scope), F2 (same class), F4 (one probed omission case). Its
156
+ report's plan-binding claim is stronger than its code.
157
+
158
+ **Leg A — strengths.** Strictly more of the P1 class is closed (F1, F2), the derivation-relevant omission
159
+ cannot happen for a frontmatter-opening record (F4), the implementation is cheaper (no extra derivation
160
+ calls) and the reason codes are explicit.
161
+
162
+ **Leg A — defects.** F5: the relevance rule is a mirror of the derive contract rather than the contract
163
+ itself, so it can drift silently; and it fails closed on any record whose first line is `---`, which is
164
+ stricter than the derivation requires (an availability cost, the mirror image of B's F4).
165
+
166
+ **Shared.** F3 (no external anchor in the cached path), F6 (a binary under a governed path is
167
+ unavailable), F10 (residual limits). Neither leg's extra checks change F3.
168
+
169
+ ## Recommendation
170
+
171
+ **Minimal combination, base B**: keep B's derivation-grounded relevance (no duplicated rules, no drift
172
+ surface, and it already answers the baseline/candidate/new/deleted class), and add A's three small
173
+ additions to B's core — the plan↔identity comparison (F1), the config-bytes↔inventory check (F2) and the
174
+ frontmatter-opener guard (F4). Cost: ≈17 lines in `hooks/scripts/lib/doc-reconciliation-core.js` plus the
175
+ three corresponding test cases; no public API, digest schema, event module or producer change; the
176
+ packaged copy is regenerated with `npm run plugin:sync`.
177
+
178
+ **If the owner selects one leg without merging**: take **A**. The P1 gaps in B are current and
179
+ demonstrated, and this PR exists to close that class; A's weakness is a maintenance coupling that can be
180
+ removed later (exporting the derive contract's classification, or porting B's witness approach) without
181
+ changing any trust guarantee. B's grounding is the better long-term shape for the P2 rule, so it is worth
182
+ recording as the follow-up. B should not be selected unmodified: F1 alone is inside the packet's stated
183
+ P1 scope, and B's documentation currently claims that scope is closed.
184
+
185
+ **Acceptance.** Leg A: accepted (no blocker-class finding; F5 is a recorded residual). Peer B: not
186
+ accepted as-is (F1); accepted once F1, F2 and F4 are applied and pinned by the three probe cases above.
187
+
188
+ This review does not certify PR readiness and does not judge the live-host provenance of either leg; the
189
+ owner decides.
190
+
191
+ STATUS: DONE