Skip to content

docs(aep): human-alignment decision doc (project brief one-pager skill) - #28

Merged
memorysaver merged 8 commits into
mainfrom
docs/human-alignment-decision
Jul 25, 2026
Merged

docs(aep): human-alignment decision doc (project brief one-pager skill)#28
memorysaver merged 8 commits into
mainfrom
docs/human-alignment-decision

Conversation

@memorysaver

@memorysaver memorysaver commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Summary

Decision doc for a new standalone top-level skill /aep-human-alignment — renders product-context.yaml into a self-contained one-pager HTML brief at docs/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

  • D1 — placement: skills/human-alignment/ as a top-level standalone skill (no category nesting, no duplicate dir); design-lens stays in patterns/ for now (per-directory install model blocks nesting a skill inside a skill) and is cross-referenced instead.
  • D2 — the artifact: vertical-scroll one-pager, four scope bands (Overview · Product · Project · Engineering) mapped to product-context.yaml; three-tense encoding, delta-gate manifest, cold-reader contract, retention of the newest three briefs.
  • D3 — presentation stack: WebGL background + keyboard band navigation + a deterministic code pipeline rendering all five diagrams through archify, embedded via srcdoc into one file; no React; the font CDN is the only primary-path network dependency.
  • D4 — hybrid honesty model: facts deterministically derived (facts JSON, the only legal source of numbers, bound declaratively via data-fact), narrative agent-authored with tense chips + authored-at stamps, statically checkable audit before delivery.
  • D5 — lean-standard skill anatomy (SKILL.md ≤ ~150 lines; template.html as single class and fact-binding source; seven Node scripts).
  • D6 — 11 checkable acceptance criteria + v3.3.0 minor bump + downstream re-pin path.
  • D7 — two framework specs the brief needs and AEP lacked: the attention set ("what needs a human") and the drift facts ("where did reality drift").

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 (both failed), 28 raw drift facts, 32 declared modules with zero paths against 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:

  1. Drift 1 named the wrong field. layer_gates[].coverage.uncovered is a /aep-build authoring worklist, so it is empty precisely when the gate never opened — all nine coverage-bearing looplia gates have uncovered: [], including L32 at 0-of-38. The spec would have derived zero drift from its own motivating finding. Now derives from criteria_total − criteria_covered; uncovered[] stays as the detail channel.
  2. Schema tolerance was section-level, not field-level. looplia's architecture.amendment_log[] entries carry only date + summary though the schema defines status: 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 a schema_absent[] record: an empty attention set is trustworthy only when schema_absent[] is also empty, and the surface must say which it is.
  3. The calibration predicate named a field that never existed. calibration.plan[] is layer · dimensions · trigger — no status, in looplia or upstream (the simulation's calibration_status came back as fifteen nulls). Respecified as plan-minus-history, matching what /aep-calibrate step 1 already does.

Design fixes:

  • Band 2 honors the two-phase gate. The reference brief rendered a scripted_passed L32 as "acceptance passed" in prose while its own anchor read scripted_passed (human acceptance pending). passed gates now yield unchipped facts; scripted_passed is admitted only under an EXP chip naming the pending human acceptance.
  • The number audit can now fail. The simulation's template injected numbers imperatively ($('ontA').textContent = FACTS.code_graph.nodes), leaving a standalone audit.mjs nothing to check — a static scan finds no prose numbers and passes vacuously. Numbers now bind as data-fact="<path>", making two checks static: every path resolves, and no digit appears in authored markup outside a binding or an anchor.
  • The architecture pipeline gets files. D3/D4 made the scanner, R1–R10, and the receipt consumer load-bearing but D5 listed no home for them (the simulation ran them as an ad-hoc Python script). Now scan-workspace.mjs / arch-rules.mjs / receipt-consumer.mjs / assemble.mjs, Node throughout.
  • Retention ruled. At a measured 3.2 MB per brief, "pruning is the owner's choice" is a policy that will not be executed. Phase 4 keeps the newest three and prunes; manifest.json gains a history[] 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 + 2 deferred), not 10 completed; control-plane incoherence is 9 layers under a now-written-down predicate (≥1 completed story under a not_started gate), 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

  1. D2 — is keep-the-newest-three the right retention default, or should the count differ?
  2. D7 — the three corrected derivations: any other predicate that names a field real consumers do not populate?
  3. D6 — acceptance 9/10/11 are new; are they the right proofs for retention, field-level tolerance, and two-phase gate honesty?

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

memorysaver and others added 3 commits July 24, 2026 13:54
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
@memorysaver

Copy link
Copy Markdown
Owner Author

Revision 2 — adversarial review folded in

Ran 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 (7957322):

New D7 — framework-level derived-view specs (the review's deepest finding: the brief can't render what the framework doesn't represent):

  • Attention set (_shared/references/attention-set.md): canonical needs-you predicates + deterministic one-ask priority. No new story state, no stored field — derived view only. Consumers: this skill now; autopilot/watch re-point later.
  • Drift facts (_shared/references/drift-facts.md): four deterministic derivations (coverage.uncovered · amendment_log pending · failure_logs · layer↔state incoherence) + optional import-graph probe (LSP/madge-class, revision-pinned). Hand-authored drift banned (OBS-2).

Key corrections:

  • D4: derive.mjs + facts.schema.json + independent audit.mjs move into v1 — evaluator independence per verification-economics; structured repair receipts, 2-round bound; evidence-language rule for narrative.
  • D2: plainness law scoped content vs. canvas (owner ruling: WebGL wash = aesthetic layer, words/diagrams = plain); delta baseline = committed manifest.json (branch-safe); canonical vocabulary defined (8 parts + 5 stages — P4 becomes a mechanism); honesty-meter chip rules restored.
  • D3: mermaid stays (owner ruling) but reframed honestly — author-side guidance, per-graph bounds incl. subgraphs, human glance gate, labeled CDN fallback, archify cross-invoke as the recorded upgrade path; free scroll (no snap) + sticky state rail.
  • D1: v1 = standalone, manually invoked (owner ruling: dev-efficiency first); loop integration → Horizon.
  • Horizon: Workflow 2 — comprehension check (owner request), wrap/autopilot integration, TUI render.
  • Acceptance: fixture with known attention signals must render the one ask (NOW provably non-empty); content SHA-256 in manifest; standalone audit run.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MEahPM4wuMp8S6VCDSXoTx

memorysaver and others added 4 commits July 24, 2026 17:11
…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
@memorysaver

Copy link
Copy Markdown
Owner Author

Revisions 3–6 — simulation-driven convergence

The doc evolved through a full-pipeline simulation against looplia (real consumer, 395 stories, live HEAD) with owner rulings after each round:

  • Rev 3 (acb3662) — cold-reader contract: every read is a first read; plain sentence primary + provenance anchor secondary; 7-word vocabulary budget; owner-language output; 5 derivation-spec fixes from the simulation.
  • Rev 4 (6fe9470) — audience-depth pyramid: ?read= removed; one document, four bands; role = scroll depth.
  • Rev 5 (3d026d2) — archify cross-invocation for the engineering band (typed IR → layout gates → repair receipts → embedded artifact).
  • Rev 6 (c778ffe) — scope band names (Overview · Product · Project · Engineering); deterministic architecture pipeline (workspace scan → rules R1–R10 → mechanical receipt consumer → archify; code = truth for edges, YAML = meaning, gap = drift; modules[].paths schema recommendation); single-file assembly (5 archify artifacts srcdoc-embedded, mermaid CDN eliminated, byte-identical re-runs in acceptance).

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

https://claude.ai/code/session_01MEahPM4wuMp8S6VCDSXoTx

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
memorysaver merged commit ad64725 into main Jul 25, 2026
@memorysaver
memorysaver deleted the docs/human-alignment-decision branch July 25, 2026 02:35
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant