docs(aep): human-alignment decision doc (project brief one-pager skill) - #28
Merged
Conversation
New standalone top-level skill /aep-human-alignment: renders product-context.yaml into a self-contained one-pager HTML brief (docs/human-alignment/brief.html). Upstreams SIBYL's human-alignment contract (six sections, three tenses, delta-gate), adopts guizang-ppt authoring discipline (template as single class source, P0 checklist) and archify's evidence-console presentation ethic (derived facts only, one main path, progressive disclosure). Decision doc only per decision-doc-first convention; implementation follows in a separate PR against this document. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MEahPM4wuMp8S6VCDSXoTx
Owner direction: docs/human-alignment/brief-<date>T<time>Z-<shorthash>.html so provenance is visible without opening the file; runs accumulate as a record, newest-by-sort is the delta baseline. Acceptance adds a filename provenance check. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MEahPM4wuMp8S6VCDSXoTx
…s + owner rulings Folded the three-lens review (SIBYL fidelity / guizang+archify integration / goal skepticism) and owner rulings into the decision doc: - D7 (new): framework-level derived-view specs in product-context/_shared — the attention set (canonical needs-you predicates + one-ask priority) and the drift facts (four deterministic derivations + optional import-graph probe); hand-authored drift banned (OBS-2) - D4: derive script + facts.schema.json + independent audit.mjs move into v1 (evaluator independence per verification-economics); structured repair receipts with 2-round bound; evidence-language rule for narrative - D2: plainness law scoped content-vs-canvas (owner ruling); delta baseline = committed manifest.json (branch-safe) instead of filename sort; canonical vocabulary defined (P4 as mechanism); honesty-meter chip rules restored; altitude column restored - D3: mermaid reframed as author-side guidance with per-graph bounds incl. subgraphs, human glance gate, honest CDN fallback wording, archify cross-invoke upgrade path; free scroll (no snap) + sticky state rail; typography roles + single palette source stated - D1: v1 manual trigger explicit; loop integration moved to Horizon - Horizon (new): Workflow 2 comprehension check (owner request), wrap/autopilot integration, attention-set consumers, TUI render - Acceptance: fixture-with-known-attention-signals proves NOW non-empty; content SHA-256 in manifest.json; standalone audit run Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MEahPM4wuMp8S6VCDSXoTx
Owner
Author
Revision 2 — adversarial review folded inRan a three-lens adversarial review (SIBYL-contract fidelity · guizang/archify integration · goal-achievement skepticism; three independent reviewers) and folded the confirmed findings plus owner rulings into the doc ( New D7 — framework-level derived-view specs (the review's deepest finding: the brief can't render what the framework doesn't represent):
Key corrections:
🤖 Generated with Claude Code |
…tion-derived spec fixes The looplia full-pipeline simulation (395 stories, d5212571) plus the owner's readability verdict produced: - D2: cold-reader contract — every read is a first read; two channels with inverted hierarchy (plain sentence primary, system id demoted to provenance anchor); seven-word prose vocabulary budget; output in the owner's language; dual reads differ in ordering only - D4: six cold-reader authoring rules (answer-first, while-you-were-away narrative, mandatory translation bound to fact ids, no naked numbers, folded queue, so-what test) + audit additions (translation-anchor 1:1, budget count) - D7: five simulation spec fixes — intent-without-evidence scoped to layers with work done (OBS-2 noise reproduced and fixed), failure-log drift limited to open stories, schema-version tolerance, field typing, paper-overlay fix; simulation evidence recorded - Acceptance #7 (prose+anchor / budget); alternatives: system-vocabulary prose rejected; Horizon: stakeholder read reduces to hiding anchors Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MEahPM4wuMp8S6VCDSXoTx
…es ?read modes Owner ruling: one document, one fixed order. Four bands — everyone / product user / product manager / engineer+architect — role adaptation is scroll depth plus disclosure, not a URL parameter. ?read= and manifest order arrays removed; stakeholder mode dissolves (stop after band 2). Band 2 (user-visible capabilities from passed layer gates + changelog) is net-new derived+authored content. Delta-gate now applies per block within bands; acceptance and D3 navigation updated; URL-parameter reads recorded as a rejected alternative. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MEahPM4wuMp8S6VCDSXoTx
Owner ruling: the deferred archify upgrade path activates now. The Author phase writes a typed architecture IR from the architecture facts (semantic types, boundaries, guided views, cold-reader two-channel labels), cross-invokes archify validate (schema + Clean Flow/Label gates, repair receipts within the 2-round bound) and deliver, and the brief embeds the companion artifact via ?embed=1. Mermaid survives only for LIFECYCLE vocabulary mini-diagrams; the degrade ladder is archify → bounded mermaid → source text. Acceptance #8 added. Simulation evidence appended: looplia 12-component IR, two receipt-guided repairs (dot enum, labelAt), delivered 614KB interactive artifact; plus the live-HEAD lessons (id-keyed changelog translations; no authored numbers). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MEahPM4wuMp8S6VCDSXoTx
…chitecture pipeline, single-file assembly Three owner rulings, proven in the looplia simulation before writing: - Bands named by scope (Overview · Product · Project · Engineering), not audience roles — role names invite self-exclusion - Architecture topology from a deterministic code pipeline: workspace-graph scanner → auditable rules R1–R10 (exclude tests, fold ubiquitous deps, cascade/domain layouts, fixed type+domain tables, transitive reduction, generated guided views, permutation row-order search) → mechanical receipt consumer → archify validate/deliver; three tiers (domain overview / package graph / declared narrative); code = truth for edges, YAML = truth for meaning, gap = drift; modules[].paths recommended as the schema binding (separate PR); tool ladder recorded (workspace graph → dependency-cruiser → AST; LSP rejected for batch) - Single-file assembly: five archify artifacts (architecture ×3, workflow, lifecycle) embed via srcdoc with light-theme seed + Blob open-in-window; mermaid CDN leaves the primary path; ~3MB cost stated with prune policy note - D4 Phase 1.5 upgraded from optional probe to the scan phase; acceptance #8 now requires byte-identical re-runs; ontology-gap evidence (20 packages vs 32 declared modules, zero overlap) recorded in D7; Horizon adds dependency-cruiser rung, Architecture Delta, sequence/dataflow triggers Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MEahPM4wuMp8S6VCDSXoTx
Owner
Author
Revisions 3–6 — simulation-driven convergenceThe doc evolved through a full-pipeline simulation against looplia (real consumer, 395 stories, live HEAD) with owner rulings after each round:
Simulation evidence is recorded in D7. Sample artifacts (looplia brief one-pager + 5 validated diagrams) were reviewed by the owner across 4 iterations. 🤖 Generated with Claude Code |
Re-derived every simulation number from the looplia repo and the surviving artifacts. The counts hold; three derivations did not survive contact with the real consumer, and the revision-6 rulings had not propagated everywhere. Derivation corrections: - drift 1 derives from coverage.criteria_total - criteria_covered, not coverage.uncovered (a /aep-build worklist, empty exactly when the gate never opened — all nine looplia gates have it empty, incl. L32 at 0/38) - schema tolerance is per-predicate, not per-section: new schema_absent[] record; looplia's amendment_log entries carry no status, so that attention-set predicate and drift 2 must skip-and-record, not go quiet - calibration derives from plan-minus-history; calibration.plan[].status exists neither in looplia nor upstream Design fixes: - band 2 admits `passed` gates as fact; `scripted_passed` only under an EXP chip naming the pending human acceptance - numbers bind declaratively via data-fact so audit.mjs is statically checkable (and provably able to fail) - D5 gains the architecture-pipeline scripts, Node throughout - retention ruled: keep the newest three, tool-side prune, manifest history[] carries the record (measured 3.2 MB per brief) Propagation of revision 6: - mermaid removed from the self-contained claim, the degrade ladder, and acceptance 4 (which now tests archify-CLI-absent) - rail labels use scope names, not role names Numbers pinned: 12 log-bearing stories are 10 closed (8 completed + 2 deferred), not 10 completed; control-plane incoherence is 9 layers under a written-down predicate, not 8 under an unstated one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn
memorysaver
added a commit
that referenced
this pull request
Jul 27, 2026
… product-context.yaml (#29) * feat(aep): human-alignment skill v3.3.0 — one-page project brief from product-context.yaml Implements docs/decisions/human-alignment.md (PR #28, revision 7). The planning layer gets a human-facing surface: one command turns product-context.yaml into a single self-contained HTML page answering where are we, what needs me, and where reality drifted from intent. Proven end-to-end against a real 396-story consumer, whose unedited output ships as the reference example in docs/human-alignment/example-looplia/. Skill (skills/human-alignment/, a fifth marketplace plugin): - derive.mjs — the only legal source of numbers; validates its own output against facts.schema.json before anything reads it - scan-workspace.mjs → arch-rules.mjs → receipt-consumer.mjs — the deterministic architecture pipeline; rules R1–R10 are executable data, and repairs come only from archify's structured receipts within a two-round bound - audit.mjs — the independent mechanical audit; the agent that wrote the prose does not grade it - assemble.mjs — srcdoc-embeds five diagrams into one file, prunes to newest 3 - template.html — the single source of CSS classes AND of the data-fact binding convention, so number provenance is statically checkable Framework specs (skills/product-context/_shared/references/): - attention-set.md — what needs a human, deterministic one-ask order, per-predicate schema tolerance - drift-facts.md — the five drift derivations; hand-authored drift is banned Tooling: - build-skills.sh materializes shared resources into top-level skills, not only product-context children — a standalone skill must carry its own copy because the skills CLI installs one directory at a time. Existing corpus byte-identical. - oxfmt ignores docs/human-alignment/example-*/ — generated artifacts are evidence, not source, and reformatting them would break their content digest. Two derivations corrected by running against real data rather than a fixture: intent-without-evidence derives from the coverage counters (coverage.uncovered is empty precisely when a gate never opened), and its layer scope excludes `ready` as well as `pending` — a dispatchable task is not a started one. Only a `passed` gate yields an unchipped capability; `scripted_passed` appears solely under an EXP chip naming the acceptance run that would settle it. Known gap: evals/skill-routing-observations.json has no entries for the three new routing cases. Those record an independent model's selection against the installed description corpus and cannot be authored by the agent that wrote the description. check-skills-package.sh fails until that probe is run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn * test(aep): independent routing probe for the 23-skill corpus Adding aep-human-alignment changed the description corpus that routing decisions are made against, so the whole suite was re-run rather than the three new cases appended — the recorded run binds to a corpus digest, and a partial update would leave 36 selections attributed to a corpus that no longer exists. Method: a subagent was given exactly one file (the 23 skill names and descriptions, plus the 39 prompts), instructed not to open any other file and not to look for the expectation list, and asked to self-report confidence. It made one tool call. The description text it saw was verified byte-identical to what the official Agent Skills parser produces before the digest was recorded. Result: 39/39 match expectations, zero regressions. One boundary probe (validate-vs-gen-eval) came back medium confidence; the rest high. The three human-alignment cases all resolved correctly, with aep-envision and aep-watch as runners-up — the two neighbours those probes were written to test. check-skills-package.sh now passes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn * docs(aep): human-alignment revision 8 — Engineering is prospective-structural Owner rulings after the implementation run, on what the Engineering band is for. (a) The band is prospective and structural, not a deeper cut of progress. An engineer needs the current structure and what the next design does to it; "where work happened / what it cost / where it failed" is Project's depth. Spine: Now · Concepts · Next · Options. (b) The ontology stops being a deployment taxonomy. Nodes are concept modules measured against the code units that carry them — derivable today, because stories[].module and files_affected are present on 396/396 stories in the reference consumer with 84% of paths resolving to a real package. (c) R7 is corrected from a naming convention to a measurement. Splitting package names on a hyphen was deterministic and worthless: 14 domains from 19 packages, 11 singletons, and it discarded 32 prose module descriptions. Determinism is a means to trust for claims about reality; a grouping is not one. (d) D8 — suggestions are allowed, as Design Option Sets with a required grammar: derived trigger, >=3 options including "leave it as is", per-option cost in the project's own measured terms, a design sketch, and a stated ranking criterion. Bare one-liner recommendations are banned. (e) Thresholds are fixed in the spec, not configurable, and all detectors run against the Next projection only. The control run earned that scope rule: on completed work the same detectors produce 5 / 3 / 68 hits, all noise. A third detector (declared-independent modules sharing files) is rejected from v1 at 68 hits with no principled cut point, rather than tuned until it looked reasonable. (f) The mining principle: when a signal looks underivable, ask what the project actually records. Revision 7's implementation broke this three times and each error shipped — cost was in stories[].cost_usd ($735.15) not the zeroed roll-up; the module-to-code binding was measurable from the work record; and the "1 name in common" figure compared declared modules against package names instead of against the modules stories are filed under (44 used vs 32 declared). Calibrated on the reference consumer: concept crowding fires exactly once (do-agent, 7 concepts, 85 files, 81% pairwise-disjoint), homeless concepts zero. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn * feat(aep): implement revision 8 — measured concept binding, prospective Engineering, Design Option Sets Brings the implementation up to decision doc revision 8 and regenerates the looplia example against it. The three false statements the previous example shipped are gone, because the signals behind them turned out to be derivable. Mining (derive.mjs): - cost rolls up from stories[].cost_usd — $735.15 across 34 priced stories, attributable per module — instead of trusting a zeroed cost.total_usd. Their disagreement is now itself a drift fact. - concept-to-code binding measured from stories[].module x files_affected: 30 of 44 concepts resolve to a real unit. Drift 5 restated accordingly; architecture.modules[].paths becomes a way to declare what is already measurable, not a precondition for measuring it. - module vocabulary drift: 44 modules used by work vs 32 declared, 13 never written down and 1 declared but never touched. This replaces the old "1 name in common" figure, which compared declared modules against package names — the wrong two sets. - structure plane: Now / Concepts / Next / Options, with the D8 triggers at their fixed thresholds, scoped to the queued-work projection only. Architecture (arch-rules.mjs): - R7 no longer synthesizes domains from package-name prefixes. Tiers are now "what exists now" (units annotated with the concepts they carry), "where the next design lands" (queued work projected onto them), and the declared narrative. The dead name-stem helper is removed with the rule it served. Surface (template.html): - Design Option Set markup and styling: trigger, options as buys/costs/design/ settled-by, and a criterion line that states how the ranking was chosen. Example regenerated at looplia 65e359c6: 31 data-fact bindings, zero unresolved; five archify artifacts green within the two-round bound; audit passes standalone; one Option Set fires (do-agent, 7 concepts, 85 files, 17 of 21 pairings disjoint) and its cleanest seam is company-assurance-incident-ops at zero shared files — correcting the by-hand reading that named authority-kernel, which shares one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn * docs(aep): human-alignment revision 9 — completeness by construction An independent generator/evaluator pass on the generated brief returned FAIL. Nine content defects; eight of them are the same defect wearing different clothes: the prose needed a fact the derivation had not produced, so the authoring agent supplied it from a diagram label, from ambient knowledge, or by counting manually — and the audit could not object, because its unit of check was the digit rather than the claim. Root cause: the facts plane was designed top-down (what should the brief show?) against a source carrying 483 populated key paths, of which the derivation reads about thirty. Every hole was a path nobody had looked at. D9 replaces hole-by-hole patching with four deterministic mechanisms: 1. Source census — enumerate every populated path in the plan file and classify it against a committed manifest as derived / ignored(with a reason) / unhandled. Unhandled paths carrying data are reported, and the brief states its own reading coverage. Closes the cost, files_affected, attempt_count and closure_status defects at once. 2. Claims bind, not numbers — every assertive block declares the facts it rests on; no uncited assertive block may exist; number-words count as numbers. One rule closes both the unbound numeral and the uncited causal claim. 3. Facts carry predicates, not raw fields — retries_exhausted, sign_off_withdrawn, root_cause_stated, completions_in_window. If the predicate does not exist, rule 2 forbids the sentence, so the derivation and the prose are forced to co-evolve. Corollary: a fact may not collapse ambiguity — ties are carried whole, or the prose will assert uniqueness. 4. Every tool declares its own coverage — a scanner reports what it did not cover, and no tool may imply totality. Owner rulings: classification is at path-template level (~100 entries, not 483 leaves), and an ignored entry must carry a reason rather than a checkmark. Recorded honestly: one of the nine (an unsorted changelog slice) is an ordinary bug that none of these mechanisms would have caught. Eight become structurally impossible; one was simply wrong code. Acceptance is not "the defects are gone" but "the defects cannot be authored": re-running against the reference consumer, the census must report the unhandled paths that produced them and the audit must reject the sentences that shipped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn * feat(aep): implement D9 — census, claim-level audit, predicates, coverage declaration The four mechanisms from decision doc revision 9, each verified against the specific defect it exists to prevent. 1. Source census (census.mjs + source-census.json) Enumerates every populated path template in the plan file and classifies it as derived / ignored(with a reason) / unhandled. Subtree rules (`a.b[].*`) let one genuine reason cover one homogeneous group; the most specific rule wins, so exceptions stay expressible. An ignore rule with no reason fails the census outright — a checkmark records that someone clicked past a field. Against the reference consumer: 486 populated paths, 55 derived, 431 ignored, 0 unhandled, read coverage 11.3%. The number is small and that is the point: it was previously unknown. 2. Claim-level audit (audit.mjs) The unit of check moves from the digit to the claim. Every assertive block must carry data-claims, an inline fact binding, or an explicit data-authored mark; number-words count as numbers. Run against the prose that shipped, it now raises 50 receipts — 18 number-words and 32 uncited assertions, the first being the headline sentence the evaluator found contradicted by the source. That is D9's acceptance bar: not "the defects are gone" but "the defects cannot be authored". 3. Predicates (derive.mjs) retries_exhausted, root_cause_stated, sign_off_withdrawn, successor_layer, completions_in_window. Each exists because prose previously inferred it: "automatic repair has already given up" (attempts used 0 of 2), "a specification and an implementation disagreeing" (both failure logs record the root as unproven), "the last thing before sign-off" (the acceptance was retired by owner decision, successor layer 41). A withdrawn sign-off now also drops the layer from the capability list. 4. Coverage declaration (scan-workspace.mjs) The scanner reports what it did not read. On the reference consumer it names four unscanned Rust crates including apps/daemon — work the same page prices at $55.09 while excluding it from "the system". Also fixed: the changelog was sliced from the tail without sorting, so the newest entries were invisible. It is 26-pairs out of order in the reference consumer, and the entries being missed were the owner decisions that closed the current layer. Ids now bind to the source index, not to list position. The example artifact is deliberately NOT regenerated in this commit: the new audit rejects its prose, which is the evidence that the mechanisms work. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn * docs(aep): record gen/eval round 2 — still FAIL, different failure mode Two independent evaluator rounds have now run against the generated brief. Both returned FAIL, and the second failed differently from the first — which is the finding worth recording. Round 1: the prose needed facts the derivation had not produced, so the agent supplied them from diagram labels, ambient knowledge, or manual counting. That produced D9 (census, claim-level audit, predicates, coverage declaration), and those mechanisms hold: the round-1 defects are now unauthorable and the round-1 prose is rejected by the current audit. Round 2, on the far side of that fix: - A queued stage is called unstarted while its only story completed hours before generation; the citation counts pending/deferred, which say nothing about that layer. - "closed by your decision last week" — the decision is dated the same day, and the anchor prints that date directly beneath the words. - "first brief, nothing to compare against" is true only because regenerating by rm+cp bypassed assemble.mjs and discarded the committed baseline. Checklist P2 fails. - The DELIVERED file fails the skill's own P0 audit with 34 uncited assertions: the audit was only ever run on the authored HTML, never after assembly. Three injected diagram captions carry numbers contradicting the prose beside them (18 vs 21 units, 30 vs 31 concepts, 8 vs 7 net-new) — partly a labelling gap, partly a code graph one commit behind the facts. - Several citations resolve without bearing their sentence: the scripted_passed count bound to a clause that means the EXP capabilities; cleanest_seam (one module, no size) bound to a sentence naming two and comparing size. The last item is the design finding. Mechanism 2 enforces that a path resolves; it cannot enforce that the path bears the claim, and a citation that resolves without bearing is worse than none because it reads verified. Recorded as an open question in eval-findings.md rather than patched — two rounds have produced two different failure modes, and a third round of the same shape would not be evidence of convergence. The example and its README are flagged as failing. This PR must not merge. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn * fix(aep): close the four pipeline defects round 2 found Each fix is verified by the defect firing before and not after. 1. Audit the delivered file, not only the authored one. Phase 3 ran before Phase 4 injected the diagrams, so nothing ever checked the artifact that ships. `--delivered` excludes embedded payloads from the claim rules — that prose is archify's, validated separately — while still checking provenance. On the round-2 artifact it drops 34 false positives and leaves the one real finding. 2. Commit-skew gate. The round-2 brief embedded a code graph one commit behind its facts, which is why three diagram captions disagreed with the prose. assemble.mjs now refuses to write when facts and code graph name different commits, and the delivered audit raises the same skew as a receipt. 3. Baseline-destruction guard. "This is the first brief, there is nothing to compare against" was true only because regenerating by rm+cp bypassed assemble.mjs and discarded the committed ledger. assemble.mjs now refuses when the manifest names a brief that is no longer present and history is empty. The destroyed baseline is restored from git, and the example now carries a real history[] with two retained briefs. 4. Diagram captions state their own scope: "18 of 21 units shown after R1/R2 reduction" rather than "18 units" beside prose saying 21. The reduced count and the raw count were both correct and neither said which it was. The example is regenerated in place at a single commit and the delivered file now passes its own audit. Round 2's remaining findings — citations that resolve without bearing their claim, a scoped measurement stated unscoped, a dependency described backwards — are NOT fixed here; they need a design answer, and they stay recorded in eval-findings.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn * docs(aep): human-alignment revision 10 — the unit is the clock, not the page Scope note first, because revisions 7-9 blurred it: this revision is about the surface's own design. The reference consumer's plan-file hygiene — stale calibration entries, gates never flipped, an unwired cost roll-up, undeclared modules — is that consumer's business and /aep-validate's. Those are evidence about what this surface makes visible, not requirements on it, and treating them as requirements is how a rendering skill grew a detector suite. D10 — The unit of delivery is the clock, not the page. Revision 9's velocity number was the interval between edits, not the survival time of a fact. Re-measured over sixty commits the bands do not share a clock: band 1 (the attention set, the one ask) survives ~110h, band 2 ~29h, band 3 and 4 ~10h. Revision 6's band split turns out to sit almost exactly on the seam in the survival curve — that decomposition was right. Fusing the bands into one file is what is wrong: to keep the fastest band true you re-author the slowest band's prose about a hundred times per fact change, and each pass is an independent draw from the defect distribution. Of eighteen findings across two evaluation rounds, two or three are staleness; the rest are authoring failures against a fact plane that was correct and twenty-two minutes old. Ruling: emit the fact plane per commit, answer "what happened since I last looked" at read time in events rather than states, and generate the orientation document per layer. The delta narrative — the design's own velocity answer — has never produced a line of output and is promoted to a first-class emission. D11 — Render; do not detect. The skill accumulated detectors because it was the surface that noticed. A finding that wants an action belongs where it can block (/aep-validate), not in a document where it narrates. The derived-view specs stay framework vocabulary that both consume. This removes the pressure that produced the detector suite. D12 — Never a private store. A reviewer proposed an owner-ledger for rulings, obligations and invariants. The insight is right; the mechanism is not. The framework already defines product.decisions[] and product.open_questions[].revisit_trigger — a private file would be a third home for a truth the schema owns, which is exactly the second-source failure D7 exists to prevent. Where a consumer invents fields the schema does not define (the reference consumer added closure_status, decision_realignment, notes, release to its gates), that is itself drift to surface. The one genuine gap is obligations: manual_pending is a boolean with no owed_by and no since, so nothing can age or escalate it — recommended to the schema, following the modules[].paths precedent. D7 corrections, the design's own: the one ask must order topologically before alphabetically (the rule selected a blocked item over its blocker), and every signal must carry a `since` because age is often the finding. D9 corrections, the design's own: the census postcondition must be adversarial (unhandled_count == 0 was satisfied at 11.5% coverage, and one templated ignore caused the one-ask defect), and claim-binding raises apparent verification without raising verification — it needs a checkable claim-to-fact relation or a downgrade from guarantee to lint. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn * feat(aep): converge on revision 10 — add the pulse, fix the one-ask ordering Two changes, both from revision 10. D7 correction: the one ask now orders topologically before alphabetically. Within a rank and layer, an item another candidate depends on comes first. The alphabetical tie-break alone selected a blocked story over its own blocker and told the reader to restart it; against the reference consumer the ask flips from FIX-L32-CANARY-502-001 to FIX-L32-SUPERVISOR-START-001, which is the one that actually unblocks anything. D10 emission 2: pulse.mjs — the read-time answer to "what happened since I last looked". It is the piece the design has specified since revision 2 and never once produced. It writes nothing, asserts nothing, and deals in events rather than states, so the failure mode behind every content defect in two evaluation rounds has no surface to occur on. Four sections: obligations with their age, transitions since the cursor, what needs a human (dependency-ordered), and open work that has stopped moving. Against the reference consumer it immediately surfaces what nine revisions of brief never did: two obligations addressed to the owner personally, 46 and 45 days old, recorded only as prose inside a gate's notes field, which no framework consumer can read and nothing ages or escalates. SKILL.md now leads with the three emissions and their clocks, and says plainly that generating the orientation document per invocation was the mistake. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn * docs(aep): regenerate the looplia example at a28fec13 with all three emissions The fact plane, the pulse, and the orientation document, all at one commit. Both audits pass — the authored file and, for the first time, the delivered one. The pulse output is captured alongside the brief so the two forms can be read against each other: the same project, one as computed events, one as careful prose. Also fixes a pre-commit defect this commit exposed. oxlint and oxfmt error rather than no-op when handed nothing they handle, and a glob alone was not enough: .json staged under a path in .oxfmtrc.json's ignorePatterns still reaches oxfmt, which filters it away and exits non-zero. A docs-only commit could not pass. Both jobs now carry a glob and oxfmt guards on the post-filter set, so an empty result is a no-op while a real formatting failure still fails. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn * feat(aep): implement D11 — detectors move to /aep-validate, the brief renders The skill had been accumulating detectors because it was the surface that noticed. A finding that wants an action belongs where it can block. Five checks move out of derive.mjs and into a shared detector: completed stories under a gate recorded as not_started; a gate status outside the defined set; a roll-up that disagrees with the record it summarizes; a module used by stories but never declared, or declared and never worked; and fields a consumer invented that the schema does not define. Against the reference consumer they find 9 blocking and 4 warnings — findings that had been narrated weekly in a document while nothing stopped. /aep-validate gains them as Step 0: mechanical, deterministic, run before any agent is spawned, exiting non-zero on a blocking finding with a fix for each. Agents cannot evaluate an artifact that contradicts itself, and spending agent judgment on what a check already decided is waste. A Control-plane coherence dimension is added to Mode A. human-alignment now imports the same detector and renders its output as drift facts. It no longer owns the logic. The detector is shared rather than duplicated: build-skills.sh materializes _shared/scripts/ into consumers on the same per-file rule it has always used for references — a skill receives what its SKILL.md names. Two copies of a drift detector drift, and a drift detector that drifts is worse than none. The existing corpus stays in sync and the build fixtures pass unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn * docs(aep): ship v3.3.0 as the pulse; mark the brief unproven Converges the release to what actually survived ten revisions and two failed evaluations: the deterministic half. The skill's description led with the one-page brief — the emission that failed both evaluations — so routing sent people at the unproven path. It now leads with what is supported: where a project stands, what is owed to a human and for how long, and what changed since you last looked. The marketplace entry and the README catalog row follow. SKILL.md now carries a maturity column. Emissions 1 (the fact plane) and 2 (the pulse) are supported. Emission 3 (the brief) ships unproven and says so, with a pointer to the committed findings, a note that its per-layer trigger is unbuilt, and the specific warning that its audit passing does not mean its claims are verified — the audit checks that claims cite facts, not that the facts bear the claims. The example directory is reframed as evidence rather than a model: the machinery passes, the prose does not, and that distinction is the finding. The pulse output for the same project sits beside it for comparison. Routing re-run: the description change invalidated the recorded corpus digest, so the whole 40-case suite was re-probed by an independent subagent under the same one-file protocol. 40/40 match. A new case covers the pulse phrasing directly, and human-alignment-direct is reclassified as a boundary probe since it now competes with envision — the probe self-reported medium confidence there, which is recorded rather than smoothed over. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Decision doc for a new standalone top-level skill
/aep-human-alignment— rendersproduct-context.yamlinto a self-contained one-pager HTML brief atdocs/human-alignment/brief-<date>T<time>Z-<shorthash>.html(filename carries generation time + commit hash), so the owner can answer where are we, what needs me, where did reality drift at a glance.Decision doc only, per the decision-doc-first convention (PR #17/#24 precedent). No schema, skill, or marketplace edits here; implementation follows in a separate PR reviewed against this document.
What it decides
skills/human-alignment/as a top-level standalone skill (no category nesting, no duplicate dir); design-lens stays inpatterns/for now (per-directory install model blocks nesting a skill inside a skill) and is cross-referenced instead.product-context.yaml; three-tense encoding, delta-gate manifest, cold-reader contract, retention of the newest three briefs.srcdocinto one file; no React; the font CDN is the only primary-path network dependency.data-fact), narrative agent-authored with tense chips + authored-at stamps, statically checkable audit before delivery.Revision 7 (2026-07-25) — re-derivation pass
Every simulation number was recomputed from the looplia repo and the surviving artifacts. The counts hold — 395 stories, 25,074 lines at
d5212571, attention set of 2 (bothfailed), 28 raw drift facts, 32 declared modules with zeropathsagainst 20 code packages, code graph 20 nodes / 68 edges, domain overview 9 components / 7 connections, delivered archify artifact 613,803 bytes, one-pager 3,218,172 bytes.Three derivations did not survive contact with the real consumer:
layer_gates[].coverage.uncoveredis a/aep-buildauthoring worklist, so it is empty precisely when the gate never opened — all nine coverage-bearing looplia gates haveuncovered: [], including L32 at 0-of-38. The spec would have derived zero drift from its own motivating finding. Now derives fromcriteria_total − criteria_covered;uncovered[]stays as the detail channel.architecture.amendment_log[]entries carry onlydate+summarythough the schema definesstatus: pending | accepted | rejected— so an attention-set predicate and a drift detector both went quiet and the surface said "all clear". Tolerance now binds per predicate, with aschema_absent[]record: an empty attention set is trustworthy only whenschema_absent[]is also empty, and the surface must say which it is.calibration.plan[]islayer · dimensions · trigger— nostatus, in looplia or upstream (the simulation'scalibration_statuscame back as fifteen nulls). Respecified as plan-minus-history, matching what/aep-calibratestep 1 already does.Design fixes:
scripted_passedL32 as "acceptance passed" in prose while its own anchor readscripted_passed (human acceptance pending).passedgates now yield unchipped facts;scripted_passedis admitted only under anEXPchip naming the pending human acceptance.$('ontA').textContent = FACTS.code_graph.nodes), leaving a standaloneaudit.mjsnothing to check — a static scan finds no prose numbers and passes vacuously. Numbers now bind asdata-fact="<path>", making two checks static: every path resolves, and no digit appears in authored markup outside a binding or an anchor.scan-workspace.mjs/arch-rules.mjs/receipt-consumer.mjs/assemble.mjs, Node throughout.manifest.jsongains ahistory[]so the record outlives the files. Briefs stay in git rather than moving behind.gitignore.Revision-6 rulings propagated to the sections that still contradicted them: mermaid is out of the self-contained claim, the degrade ladder, and acceptance 4 (which now tests archify-CLI-absent); the nav rail labels bands by scope, never by role.
Numbers pinned: the 12 log-bearing stories are 10 closed (8
completed+ 2deferred), not 10 completed; control-plane incoherence is 9 layers under a now-written-down predicate (≥1completedstory under anot_startedgate), not 8 under an unstated one.Sources
SIBYL
docs/human-alignment/(contract + measured failures OBS-1/3/5) · guizang-ppt-skill (single-file HTML authoring discipline) · tt-a1i/archify (evidence-console presentation ethic).Review focus
Note
The artifacts cited as evidence were generated at revisions 5–6 (looplia
d5212571/8641b716). Revision 7's corrections were verified by re-deriving the numbers from the looplia repo, not by regenerating the brief — regeneration requires the pipeline that the implementation PR builds.🤖 Generated with Claude Code
https://claude.ai/code/session_01EDTHXC2N5mDL1DtFXopAWn