feat(meta-factory): Phase 5+6 — L2 Research Agent + L3 Synthesizer Path A (deterministic v1) - #5
Merged
Merged
Conversation
…rompt Layer 2 Research Agent v1 entry research per EXECUTION-PLAN §5.5: 6-capability matrix × AIF/LangGraph/Anthropic SDK context7 queries → 5 build + 1 strong reuse (skill-context sink) + 2 transitive reuses. Architectural pivot: v1 ships deterministic-curated (no LLM), mirroring Phase 4 detector's "deterministic bridge" playbook. LLM-driven research deferred to v2 trigger (first real consumer or Phase 8 acceptance test). Phase 5/6 reordering vs EXECUTION-PLAN §6: L2 → Phase 5, L3 → Phase 6, L4 Validator → Phase 7+. Rationale: validator gates synthesized output; without L2/L3 there is nothing beyond Phase 2 manifest meta-tests to gate. Closes [open-questions.md §13.7] symbolic drift detection v1 in Task 5.
ResearchPlan = top-level Layer 2 output: framework + version + patterns[] + missing[] + drift. ResearchEntry per pattern with provenance + extras escape hatch (research §5 risk mitigation). DriftReport populated only in --self mode. JSON Schema mirrors TS types 1:1 for runtime Ajv validation in load.ts.
…ware loader
Store layout: store/<framework>/<major>.x/<patternId>.json + store/shared/<patternId>.json.
Loader resolves: exact-major → previous-major → shared/, sorted by id, skips missing
patterns rather than throwing.
6 entries hand-authored: next/16.x/{nextjs-app-router,nextjs-pages-router,
react-server-components}, next/15.x/nextjs-app-router (diff-mode test pair),
shared/{tailwind-v3-config,tailwind-v4-css-tokens}.
Each entry validated against research-plan.schema.json#/definitions/ResearchEntry
on load via Ajv — malformed throws ResearchEntryError loudly per project tenet.
10 tests: 7 loader scenarios (exact, semver coerce, version variant, shared
fallback, missing skip, mixed sort, framework=null) + 3 schema invariants.
ALLOWED_SOURCES = static map of allowlist key → trusted hostnames. validateProvenance enforces: - key exists in registry - URL parseable - https-only (no http downgrade) - hostname matches a registered host (exact or subdomain) Wired into load.ts: every loaded entry's provenance items validate on load; failure throws ResearchEntryError loudly (no silent skip). 7 tests paired positive/negative: exact-host, subdomain, key-mismatch host, unknown key, malformed URL, http rejected, registry exposed.
diffPlans(a, b) → ResearchDelta { added, removed, modified, frameworkChanged,
versionChanged }. Granularity = entry.id as join key; modified detection via
stable JSON hash so key-order changes alone do not produce false churn.
7 tests: identical empty, added, removed, modified by content, key-order
stable (negative — no false modify), framework/version transitions, mixed
delta with stable sort.
….7 v1) detectDrift(repoRoot) scans 3 canonical own-doc sources (skills/SKILL.md, references/overview.md, references/ai-traps.md) for two drift kinds: - term-presence: principle missing in ≥2 sources - modal-verb: principle has divergent MUST/SHOULD/MAY strength across sources (same-line modal attribution to avoid neighbour-principle false positives) 5 canonical principles tracked: 5-layer framework, AST over grep, paired negative tests, mutation testing, two-AI review. Real-repo canary surfaced one legitimate drift on first run: 'paired negative tests' was only documented in skills/SKILL.md. Closed by adding bullet to overview.md Layer 2 + new anti-pattern #10 (tautological tests) to ai-traps.md — substantive additions, not stuffing. Zero mismatches at HEAD. Operationalizes open-questions §13.7 first half (symbolic). Behavioral and embedding-based v2/v3 deferred per phase-5-research §6 watch-list. 4 tests: no-drift fixture (zero mismatches), with-drift fixture (term-presence + modal-verb both fire), missing-source error path, real-repo canary.
index.ts exports only research(detection: DetectionResult) → ResearchPlan plus types, enforcing Planner-Executor module-surface contract: no file-write helpers leak through this public boundary; L3 in Phase 6 imports the schema, not internals. cli.ts (51 LOC) supports four modes: - <projectRoot> default → ResearchPlan (drift: null) - --self → ResearchPlan with drift populated for own repo - --diff <a> <b> → ResearchDelta JSON - --pattern <id> → filter ResearchPlan.patterns to one entry package.json: bin rules-as-tests-research, exports ./research, script research. Smoke-tested: --self emits empty drift on root repo (post-Task-5 doc fix); --diff identical plans → empty delta.
… snapshot
framework-self-research CI job mirrors framework-self-detect pattern:
- step 1: diff research --self output against expected-self-research.json
(L2 invariant b: snapshot stability)
- step 2: assert .drift.mismatches.length == 0 across the 3 canonical
self-application sources (L2 invariant a: drift-free at HEAD)
Frozen snapshot captures own repo's L2 output: framework=null (ts-server),
patterns=[], missing=5 known packages, drift={zero mismatches}.
snapshot.test.ts mirrors detector/snapshot.test.ts pattern for local CI parity.
actionlint + zizmor clean. Full regression: principles 24/24, core 153/153,
preset 38/38, all 3 workspaces typecheck clean.
Verification: 9/9 probes green; principles 24/24, core 153/153, preset 38/38, typecheck clean, actionlint+zizmor clean, both L2 invariants closed. Self-application score 9/10 — drift detection non-vacuous (caught + closed real drift in skills/ on first run), snapshot point-in-time stable. Time vs plan: <<1h wall-clock vs 6h orchestrator-path estimate (Opus 4.7 burn-mode direct execution; mirrors Phase 4 compression pattern). 7 open questions surfaced for Phase 6 entry; key one — L3 scope decision (manifest entries vs ESLint config vs probes vs RULES.md fragments — all of above for v1 or subset). EXECUTION-PLAN §6 numbering swap (L2/L3/L4 reordering) tracked as closing item for Phase 6 retro.
…rompt Layer 3 Synthesizer Path A v1 entry research per EXECUTION-PLAN §5.5: 8-capability matrix × AIF aif-implement/aif-plan/aif-loop + ESLint flat config + typescript-eslint queries → 5 build + 2 strong reuse (manifest schema for SynthesizedRule shape, transitive deps) + 1 deferral (canonical regen ≤5% diff to Phase 6 v2 / Phase 7). Architectural pivot: v1 ships deterministic-curated (no LLM), mirroring Phase 5 playbook. 3 recipes hand-authored (one per Next 16 pattern with a Phase 5 ResearchEntry). Tailwind recipes deferred — no canonical preset to anchor against. Phase 6 = L3 only (without L5 Installer); EXECUTION-PLAN §6 numbering swap covering Phase 5/6/7 reordering tracked as Phase 6 retro closing edit.
SynthesizedRule shape intentionally mirrors rules-manifest.schema.json RuleEntry semantics — generated rules indistinguishable from manual ones at validation time (Phase 6 reuse decision 6.7). ID pattern '^G[0-9]+$' marks generated rules visually distinct from manual R-rule corpus (R1-R20, IR1-IR6). ManifestCheck union mirrors core's existing Check shape; provenance back- references Phase 5 ResearchPlan source so synthesized rules track research lineage.
…terns Each recipe maps Phase 5 ResearchEntry pattern → SynthesizedRule template: - nextjs-app-router → no-restricted-imports forbidding 'next/router' under app/ - nextjs-pages-router → manual migration check (Pages Router removed in Next 16) - react-server-components → enable existing 'rules-as-tests/no-server-imports-in-client' Path A constraint: configuration of existing plugins / preset rules only. Recipe 3 references the preset's already-shipped custom rule (no AST gen). Recipe 2 is manual — codemod-shaped migrations are not lintable per file. Hand-authored, committed; mirrors Phase 5 store posture.
synthesize(plan: ResearchPlan) → SynthesisPlan. Recipe lookup by entry.id; framework filter via recipe.appliesTo; sequential G1, G2, ... IDs in input order. Skips patterns without matching recipe (Tailwind under Next plan) and skips all when plan.framework=null (own-repo case). Output validated against synthesis-plan.schema.json on every call; malformed throws SynthesisPlanError loudly. 8 tests: empty plan, single pattern, sequential IDs, missing recipe skip, framework-null skip, framework-mismatch skip, rulesMd id substitution, eslint config merge.
emit(plan, outputDir) writes 3 files: rules-manifest-additions.json (keyed by rule id), RULES-additions.md (header + plan.rulesMd), eslint-rules- snippet.json (plan.eslintConfigSnippet verbatim). Throws EmitError when outputDir is missing or not a directory — no auto-mkdir; caller's responsibility (avoids accidentally creating paths on typo'd CLI arg). Idempotent: same plan + same outputDir → byte-identical output across repeated calls. NOT exported from index.ts (Planner-Executor segregation per Phase 6 research §3.4): only CLI imports emit.ts directly. 5 tests: empty plan → 3 files with empty bodies, populated plan with G1 rule, idempotence (byte equality across repeated emit), missing dir, non-directory path.
index.ts exports only synthesize() + types per Planner-Executor contract; emit.ts is direct-path-imported by cli.ts, never via public boundary. cli.ts (52 LOC) supports four modes: - <projectRoot> default → detect → research → synth → JSON - --from-research <path> → load ResearchPlan from disk → synth → JSON - --output <dir> → also call emit() to write 3 artifact files - --pattern <id> → filter SynthesisPlan.rules to research.entryId === id package.json: bin rules-as-tests-synth, exports ./synthesizer, script synth. Smoke-tested: own-repo CLI emits framework=null + 0 rules (no patterns; synth correctly skips when no recipes apply).
next-16-fixture/ stack: package.json (next@^16.0.1 + react@^19), app/page.tsx (triggers nextjs-app-router pattern), pages/index.tsx (triggers nextjs-pages- router), src/widget.tsx with 'use client' (triggers react-server-components). All 3 Phase 6 recipes apply → 3-rule SynthesisPlan with G1/G2/G3. Frozen snapshots: - expected-self-synth.json: own repo, ts-server, framework=null, rules=[] - expected-fixture-synth.json: next-16 fixture, 3 rules, full check+examples+research Two snapshot tests verify byte-equality on round-trip detect→research→synth. L3 invariant a (round-trip snapshot stability) closed point-in-time. L3 invariant b (canonical regen ≤5% diff vs preset-next-15-canonical) deferred with documented split-point in retros/phase-6.md.
Mirror of framework-self-detect + framework-self-research patterns: - step 1: synth on own repo, diff against expected-self-synth.json (L3 invariant a: empty plan baseline for ts-server) - step 2: synth on packages/core/synthesizer/fixtures/next-16-fixture, diff against expected-fixture-synth.json (3-rule plan with all 3 recipes firing) Both diffs use jq -S sort + diff for deterministic comparison. actionlint + zizmor clean.
…ing edit Verification: 9/9 probes green; principles 24/24, core 168/168 (124 detector + 29 research + 15 synthesizer), preset 38/38, typecheck 3 workspaces clean, actionlint+zizmor clean. L3 invariant (a) round-trip snapshot stable; (b) canonical regen ≤5% diff explicitly deferred to Phase 6 v2 / Phase 7 with documented split-point. Self-application score 8/10 — round-trip stable; canonical regen deferral acknowledged as debt, not architectural failure. Time vs plan: <<1h wall-clock vs 6h orchestrator-path estimate. Same Opus 4.7 burn-mode compression as Phase 4 + Phase 5. EXECUTION-PLAN.md §6 closing edit: discharge of Phase 5/6/7 reordering tracked across retros 5 and 6 — Phase 5 = L2 Research, Phase 6 = L3 Path A, Phase 7 = L4 Validator + L5 Installer. Phase headings retained for diff hygiene; mapping documented at top of §6. 7 open questions surfaced for Phase 7 entry — key one: 6-gate L4 Validator triage (which gates ship Path A v1 vs deferred).
This was referenced May 8, 2026
artyhoo
added a commit
that referenced
this pull request
May 8, 2026
Closes 2 MAJOR + 1 MINOR review findings on PR #13: - M1 — A3 SSOT entry #5 was added with 1 phrasing; PROMPT Hard Constraint #10 strictly requires ≥3 phrasings BEFORE adding SSOT entry. Added 2 more context7 query-docs phrasings against /anthropics/anthropic-sdk-typescript covering cache_control TTL options, max_uses budget, server_tool_use.web_search_requests counter, Usage interface token-counter independence. Updated §4.A3 with 3-phrasing log + production-tracking surface details (strengthens SSOT #5 ADOPT-WHEN-TRIGGERED claim). - M2 — A1 ROI rigor: PROMPT §6 T3 explicitly named Cody and Aider as candidates; T3.2 covered only Cursor + Continue.dev + Factory. Added Cody (Sourcegraph) + Aider lookups. Both confirm: Cody's cody.contextFilters / *.rule.md and Aider's .aider.conf.yml are AGENT-side configuration (model selection, repo filters, prompt guidance), NOT ESLint rule pick-from-menu. 5-candidate coverage reinforces «no LLM-pick-of-ESLint-rules analog in production» negative-existence claim — A1 DEFER verdict strengthened, not weakened. - m1 — retro Verification block #4 said «10 trailer lines» but actual count is 11 (T5 skipped + T6 retro trailers were missing from enumeration). Corrected to 11 = 3+1×8 across 9 commits. No verdict change in §5 matrix; ROI thesis still closes negative. SSOT entries #4, #5 unchanged. Phase 9 implementation scope (A6/A7/A8/A9 BUILD; A1-A5 DEFER) unchanged. File sizes after T7: phase-9-entry-research.md 182 LOC (≤200); retro 115 LOC (≤200); SSOT 96 LOC (≤500). Principle 08 7/7, 246/246 core tests, 9/9 verdict rows match acceptance regex. Prior-art: prior-art-evaluations.md#5 (web_search_20250305 — 2 additional context7 phrasings close M1 violation of Hard Constraint #10; ≥3 phrasings discipline now satisfied for SSOT entry add). Prior-art: prior-art-evaluations.md#4 (Factory ESLint Plugin — Cody + Aider lookups close M2 coverage gap; 5-candidate base reinforces negative-existence claim driving A1 DEFER).
artyhoo
added a commit
that referenced
this pull request
May 8, 2026
Phase 8.8.1 addendum push-based health check on 12 non-cascade §13.x triggers (excluding §13.2 narrative, §13.3/§13.6/§13.7/§13.9 closed, §13.11 cascade, §13.10 #5 cascade, §13.15 unused). For each entry: decompose trigger into observable signals → run verification probe → classify FIRED / STILL ARMED / CASCADE-DEPENDENT. Result: 12/12 STILL ARMED or PENDING T7. Zero FIRED. No per-fire trigger-fire-§<N>.md patches needed. Probes consulted: - §13.1: research-store file count (12 at 1-pattern-per-file granularity); - §13.4 / §13.5 / §13.10 #4 / §13.12 / §13.13: consumer evidence (none); - §13.8: self-application.md §3 row count (9, no 10th proposal); - §13.10 #1: Phase 8 closure status (no curated-store gap); - §13.10 #2: Phase 9 entry coverage gap recorded f92f60b — DEFER carries forward; - §13.10 #3: Phase 9 implementation scope (housekeeping only — no new pattern); - §13.14: rules-lock.json schemaVersion = 1 (no bump); - §13.16: PENDING T7 self-review. Sweep adds value most when external signals (consumer issues, version bumps) accumulate between sessions OR a phase fires a trigger the originating session didn't notice. Both vectors quiet at 2026-05-08; unsurprising outcome. Re-sweep cadence: next phase entry research session. T6 distillation folds the sweep methodology into rule §1 as 6th checklist item. Prior-art: skipped — docs-only sweep report companion to T5.5 audit, no new capability surface or explicit dependency added (per CLAUDE.md capability-commit definition).
artyhoo
added a commit
that referenced
this pull request
May 8, 2026
Verification artifact for Phase 8.8.1 hard constraint #5 «apply principle to itself». Walks the original Phase 9 entry §4.A1 lookup through .claude/rules/phase-research-coverage.md §1 checklist; tests whether the rule, had it been active before T3.2 close, would have caught the AIF /aif-evolve + Oh My ClaudeCode coverage gap recorded in f92f60b. Result: 5/6 §1 items independently catch the gap (§1.1 own-stack / §1.2 category / §1.3 semantic-distance / §1.4 adversarial / §1.5 prompt-list ≠ complete). §1.6 (trigger sweep) is N/A — it covers armed-not-fired triggers, not missed candidates within a fired trigger. §2 self-reflection prompts also pass: §2.2 specifically would have surfaced that Phase 5 / Phase 6 actively engaged AIF /aif-evolve and documented its post-hoc nature — Phase 9 entry had prior-knowledge available but did not consult it (a prior-research-not-reused regression the prompt would have caught at retro time). §13.16 self-trigger transitions from PENDING T7 → STILL ARMED (observed-zero-FP-on-self-application; foundational datapoint, not yet 3 sessions for retire path). Methodology validated. Rule ships GO, not REVISE. Prior-art: skipped — docs-only audit-trail document for self-application verification, no new capability surface or explicit dependency added (per CLAUDE.md capability-commit definition).
artyhoo
added a commit
that referenced
this pull request
May 13, 2026
…ale evidence #38 CodeRabbit: rationale point (d) «Component A+B covers 3/4 incidents» was stale — PR #51 is incident #5; Component A did NOT catch quantifier confabulation. Struck in-place with 2026-05-13 note. Trigger column updated. #41 Danger JS: ADOPT. Strongest production-grade analog for machine-verifiable PR-body validation. Direct problem-class match (same domain, paradigm). SSOT #38 deterministic vacuum filled. Used by React Native, Yarn, ESLint, Apollo. dangerfile.ts pattern maps to §1.7 schema check (Mechanism C). Verdict reversed from initial DEFER after build-vs-reuse principle challenge — DEFER was path-of-least-resistance rationalisation. Prior-art: prior-art-evaluations.md#41 (Danger JS, verdict ADOPT — production analog for machine-verifiable PR body validation; build-vs-reuse properly applied after maintainer challenge 2026-05-13)
artyhoo
added a commit
that referenced
this pull request
May 13, 2026
…ale evidence #38 CodeRabbit: rationale point (d) «Component A+B covers 3/4 incidents» was stale — PR #51 is incident #5; Component A did NOT catch quantifier confabulation. Struck in-place with 2026-05-13 note. Trigger column updated. #41 Danger JS: ADOPT. Strongest production-grade analog for machine-verifiable PR-body validation. Direct problem-class match (same domain, paradigm). SSOT #38 deterministic vacuum filled. Used by React Native, Yarn, ESLint, Apollo. dangerfile.ts pattern maps to §1.7 schema check (Mechanism C). Verdict reversed from initial DEFER after build-vs-reuse principle challenge — DEFER was path-of-least-resistance rationalisation. Prior-art: prior-art-evaluations.md#41 (Danger JS, verdict ADOPT — production analog for machine-verifiable PR body validation; build-vs-reuse properly applied after maintainer challenge 2026-05-13)
artyhoo
added a commit
that referenced
this pull request
May 21, 2026
…self-audit §11.1 interim) (#96) Implements Option (ii) — the E-checklist Stop-gate interim from the merged autonomous-self-audit R-phase (#95 §10.5/§11.1). Extends the live Stop hook with a deterministic scan that enumerates factual-claim shapes (numeric counts, file:line citations, negative-existence) in the last assistant turn and appends an item-specific re-verify instruction — targeting the at-write-time factual class (incidents #1 "4+ files", #5 ":30", #2 negative-existence) that the generic recap nudge does not force. Fires on claim-PRESENCE regardless of turn length (covers short turns the long_text gate skips). No LLM, no external call (no-paid-llm-in-ci). Honest limit: raises salience, does not structurally force compliance. Also: portable last-assistant-line extraction (grep|tail, was BSD-only tail -r) so the companion test can run on Linux/CI. New behaviour test tests/hooks/eot-claim-scan.test.sh (6 sub-tests incl. mutation) registered in audit-self.yml — the Q-D recursive backstop: the drift-catcher hook is itself caught by a test if it silently breaks. Prior-art: prior-art-evaluations.md#20 (Claude Code hooks API, ADOPT) — extends existing Stop-hook substrate, no new surface. Agent Verifier (REFERENCE/ADAPT per #95 research-patch §5.1) — session-executed verifier pattern; this auto-fires it at the AI's own claims. No new dependency.
artyhoo
added a commit
that referenced
this pull request
May 21, 2026
…(N2 #5, Commit A) (#105) ADAPT of Superpowers' «NO SKILL WITHOUT A FAILING TEST FIRST» — idea only, no dependency (substrate-pure per DECISION=C). Design-then-test split mirroring 11-build-first-reuse-default.design.md (Commit A = design; Commit B = test ≤2wk). Honest scope correction: this is a NEW principle (slot 15), not an extension of principle 02 — principle 02 checks rules-manifest.json code-rule entries (examples.bad/good), which SKILL.md does not have. The paired-negative idea is re-expressed against the skill artifact as a documented failure-without-skill block. Scope = in-repo skills only (.claude/skills/* + skills/*); grandfather existing 5 with a 2026-05-21 cutoff (principle-09 precedent) so CI stays green and the requirement is forward-going. One convention choice (marker form) surfaced for maintainer at Commit B per reviewer-discipline. No behaviour change; no test added; CI untouched. Prior-art: skipped — design-doc markdown, no new capability (no dep, no executable code; companion test deferred to Commit B).
artyhoo
added a commit
that referenced
this pull request
May 21, 2026
…ommit B) (#112) Ships the executable test for principle 15 per its design sketch (Commit A, #105). Each in-scope SKILL.md not in the EXEMPT_SKILLS allowlist must carry a body-section paired-negative block (`## Without this skill` + `## With this skill`, both non-trivial and differing — anti-tautology, mirroring principle 02). Grandfather = explicit EXEMPT_SKILLS allowlist (mirrors principle 09's EXEMPT_PATTERNS mechanism, NOT a date — the design's "date cutoff" wording is corrected to "allowlist" in §3/§5/§6/§7/§10). Self-test: positive + mutation 1a (no Without) + 1b (no With) + 2 (tautology) + 3 (exemption load-bearing). All 5 current skills grandfathered → CI stays green. ADAPT of Superpowers' «NO SKILL WITHOUT A FAILING TEST» (idea, no dependency; substrate-pure). SSOT #55 registered in this commit (#54 taken by Aider run_cmd via #110). §1.7 forward-check: principle 15 complies with build-first-reuse-default (ADAPT verdict, SSOT #55, zero Superpowers dep — substrate-pure per DECISION=C); no-paid-llm-in-ci (pure structural parse, no LLM); doc-authority-hierarchy (companion design.md carries header at packages/core/principles/15-skill-paired-negative.design.md:4); reviewer-discipline (marker form was maintainer-decided, not executor-picked). Mirrors principle 02's anti-tautology at packages/core/principles/02-paired-negative-test.test.ts:80. §1.7 backward-check: new rule scope = in-repo SKILL.md (.claude/skills/* + skills/*). Complete sweep satisfied by grandfather — all 5 current skills in EXEMPT_SKILLS at packages/core/principles/15-skill-paired-negative.test.ts:34; the exemption itself carries the load-bearing mutation-3 self-test at packages/core/principles/15-skill-paired-negative.test.ts:197 (proves the allowlist is load-bearing — same headerless skill passes IFF its path is in EXEMPT_SKILLS). No skill forced to change. Prior-art: prior-art-evaluations.md#55 (Superpowers TDD-for-Skills, verdict ADAPT — idea re-expressed for the SKILL.md artifact as principle 15; no dependency, substrate-pure).
artyhoo
added a commit
that referenced
this pull request
Jul 2, 2026
…solved) + implementation plan (#849) * docs(kickoff): rule-research-trust-tiers — tiered registry-derived docs-trust to replace hardcoded allowlist R-phase inlined: 5-thread deep-research 2026-07-02 (registry-metadata trust anchoring incl. abuse evidence, TUF/cargo-vet/TOFU vocabulary, 2025-26 docs-channel injection incidents EchoLeak/Copilot-CVE/lethal-trifecta, ContextCrush context7 incident, allowed_domains semantics survey). Design: Tier 0 builtin / Tier 1 auto-derived from LOCAL installed-package metadata scope-locked to the same package / Tier 2 cargo-vet-style committed ack records; offline factory preserved; Path B re-tightening trigger; 4 DECISION-NEEDED for maintainer. Prior-art: prior-art-evaluations.md#5 (allowed_domains, trigger now fired) + kickoff §3 external table (10 candidates with verdicts); SSOT entries to be appended per stage S-obligations * docs(kickoff): §9 maintainer direction — generate-first delivery, presets demoted to snapshot-oracles Records the 2026-07-02 maintainer directive: generation is the primary rule-delivery path for ALL stacks; presets become (1) regression oracles (EXECUTION-PLAN §1 diff-budget criterion becomes shipped CI), (2) explicitly-dated cold-start fallbacks, (3) authoring examples. Sequencing: trust-tiers S1-S2 first (generation for arbitrary stacks requires Tier 1/2 provenance), then a generate-first-delivery umbrella with its own R-phase. DECISION-NEEDED #5 added. Prior-art: skipped — kickoff §9 direction note, no new capability * docs(kickoff): rule-research-trust-tiers — hardened kickoff, all 7 DNs resolved (deep-research round 2) + implementation plan
artyhoo
added a commit
that referenced
this pull request
Jul 5, 2026
/#921) (#923) ## Summary A real `git push` from a consumer install is hard-blocked by 8 checks in `packages/core/hooks/pre-push.ts` that reference **maintainer-only paths** a consumer never receives (`install.sh` ships only `packages/core/{hooks,eslint-rules}`). The absent paths make vitest exit 1, tsx `ERR_MODULE_NOT_FOUND`, npm `ENOENT`, or a raw `ENOENT` bubble → "pre-push hook crashed". `check:shields-up` never caught this — it verifies the hook is *wired*, not that the check chain *runs*; only a real push surfaces it. This wraps each maintainer-only section in the same `existsSync` consumer-skip guard its sibling sections (3b–3f/4b) already use. Closes #920, #921. ## Changes - **`packages/core/hooks/pre-push.ts`** — 8 consumer-skip guards: - #1 §3 self-test → guard on `packages/core/audit-self/audit-ai-docs.test.ts` - #2 §4 render drift → guard on `packages/core/render/render-rules.ts` - #3 §5–5d meta-tests → one `coreMetaTestsAvailable` boolean (`packages/core/package.json`) over all four sites - #4 §6 spec-validate → guard on `packages/core/spec-validation/validate-batch-spec.ts` - #6 §7 prior-art / #7 §1.7 → one `isFrameworkRepo` boolean (SSOT register presence — a framework-authoring gate unsatisfiable on a consumer) - #5 cmd-script-liveness / #8 guard-liveness → one `hasRulesManifest` boolean (`packages/core/manifest/rules-manifest.json`) - **`packages/core/hooks/pre-push.consumer-layout.test.ts`** (new) — behavioral regression test (runs in CI via `test:hooks`) that spawns the real orchestrator against a fixture consumer layout (exact `install.sh` copy-list, every maintainer-only path absent) and asserts `exit 0`; paired-negative re-plants `packages/core/package.json` to prove the §5 guard is load-bearing. ### Design note (deviation from the issue's literal fix for #5/#8) Blockers #5 and #8 share one `rules-manifest.json`-existence guard rather than the issue's "skip-loudly catch" fallback. A consumer has no manifest rules to check, so skipping is semantically correct; keying on the manifest also keeps guard-liveness's ESLint-stack import off the consumer path entirely (the pnpm-strict `@typescript-eslint/parser` non-hoist, #8) **while preserving the maintainer's loud-die-on-real-breakage** — the section still runs fully wherever the manifest exists. ### Backward sweep Enumerated every `run()`/`requireTool()`/`import()` call site in `main()`. The only unconditional external calls left unguarded are **zizmor** (§2 — scans the rendered `.github/workflows/` that `install.sh` delivers to consumers) and **lychee** (§8 — already skip-loudly on absent binary). Both are genuinely consumer-appropriate and correctly excluded from the 8. ## Prior-art consult - [x] The new ≥80-LOC test file is flagged as a capability commit by the LOC-based detector; it carries `Prior-art: skipped — …` per the CONTRIBUTING escape hatch for hook-flagged non-capability additions (test + reuse of the existing sibling guard pattern, no new capability). - [x] No new capability area surfaced — the fix reuses the `existsSync` guard pattern already established at sections 3b–3f/4b; no SSOT entry added or matched. ## Test plan - [x] `npm --prefix packages/core run test:hooks` green (48 files / 687 tests, incl. the new consumer-layout regression + paired-negative) - [x] New consumer-layout test: POSITIVE (maintainer paths absent → exit 0) + NEGATIVE (planted `packages/core/package.json` re-engages §5) both pass - [x] `tsc --noEmit` + `prettier --check` clean on both changed files - [x] Pre-push hook ran on push (maintainer repo — all guards evaluate true, every section runs as before) - [x] Branched from `origin/staging` so the 2 unrelated in-flight ahead-commits (settings/SSOT/principle-31 drift) and their pre-existing `harness-config-drift`/`rule-channel-degradation` failures are excluded — verified those 5 tests pass on this base ## §1.7 Self-discipline check (REQUIRED if PR touches discipline-bearing files) ### §1.7 Skipped: mechanical bug fix to hook enforcement code (pre-push.ts) reusing the existing sibling existsSync consumer-skip guard pattern — introduces no new discipline rule, so no forward/backward rule-scope sweep applies
artyhoo
added a commit
that referenced
this pull request
Jul 11, 2026
…rrides where unavoidable (#980) Fixes all 16 open Dependabot alerts (triage-first, per-alert rationale below). Two atomic commits: lock/manifest bumps; drizzle fixture pins. No new dependencies — overrides entries and in-range bumps only; not a capability commit. ## Per-alert disposition | Alerts | Package | Fix | Mechanism | |---|---|---|---| | #17-#24 (7×, incl. **critical** CVE-2026-33937) | handlebars 4.7.8 → 4.7.9 | root lock | `eslint-plugin-boundaries ^5.0.0 → ^6.0.2` in `packages/preset-react-spa/package.json:26` — 6.0.2 pins `@boundaries/elements 2.0.1` → handlebars 4.7.9. Chosen over also-available ^7.0.2 as the smaller major jump with the same security outcome. The shipped template `packages/preset-react-spa/templates/eslint.config.react.mjs` is unchanged: v6 keeps the explicitly-configured legacy `element-types` rule + `boundaries/elements` settings working. | | #4, #5 (CVE-2026-8723) | qs 6.15.1 → 6.15.2 | both locks | `overrides` in root `package.json` + `packages/core/package.json` — **unavoidable**: latest typed-rest-client (3.0.0) still pins vulnerable qs 6.15.1 exactly (verified against the npm registry). | | #27 (CVE-2026-53550) | js-yaml 4.1.1 → 4.2.0 | root lock | `overrides "js-yaml": "4.2.0"` — parent markdownlint-cli2 pins exact 4.1.1; its fixed release 0.23.0 requires node>=22 while CI runs node 20, so the parent bump is blocked. Exact spec matches packages/core's direct-dep spec (npm direct-dep override rule). | | #12 (CVE-2026-48988) | markdown-it 14.1.1 → 14.3.0 | root lock | `overrides "markdown-it": "^14.2.0"` — same markdownlint-cli2 exact-pin reason. | | #10, #13 (CVE-2026-49356) | @babel/core 7.29.0 → 7.29.7 | both locks | in-range `npm update` (parents allow ^7.x / ~7.29.0). | | #7 | esbuild 0.28.0 → 0.28.1 | packages/core lock | in-range `npm update` (tsx ~0.28.0, vite ^0.28.0). Root esbuild was already 0.28.1. | | #16, #28 (CVE-2026-39356, high) | drizzle-orm ^0.40.0 → ^0.45.2 | 2 fixture manifests + stub | `packages/core/detector/fixtures/hono-drizzle-monorepo/apps/api/package.json:5`, `packages/core/research/fixtures/tier1-single-root/package.json:3`, stub `.../node_modules/drizzle-orm/package.json` bumped in lockstep. Consuming tests verified version-insensitive (name-based detection; `research-plan.json` has `version: null`) — fixed, not dismissed. | ## Notes - **Synth bundle deliberately NOT regenerated:** the bundle is built by ROOT esbuild (`scripts/build-synth-bundle.sh:17` uses `$ROOT/node_modules/.bin/esbuild`), which was already 0.28.1 and is unchanged; the packages/core esbuild bump is a non-feeding transitive. `NODE_ENV=development build-synth-bundle.sh --check` green after fresh `npm ci` of both locks. - **Consumer note (preset-react-spa):** boundaries v6 changes the `dependency-nodes` default from `["import"]` to `["import","export","require","dynamic-import"]`. Consumers may see new (legitimate) `boundaries/element-types` findings on `export … from` / `require()` / dynamic-import edges — stricter, not broken. - **Expected `npm ls` marker:** `invalid: qs@6.15.2` under typed-rest-client is the documented override-forced exact-pin violation (the point of the fix); no CI gate runs `npm ls`. ## Verification - Full local CI-equivalent gate set green: typecheck, full packages/core suite (2288 tests, 0 failed), `format:check`, `NODE_ENV=development build:synth-bundle:check`, `render-rules --check`, `render-rule-index --check`, install-sh `gh-534-arch-boundaries` + `f17-lint-rules-planted-violation` + `byte-identical` (fingerprints unchanged — no SNAPSHOT_MODE regen needed). - Lock integrity independently re-verified from clean state: `npm ci` (root) and `npm ci --prefix packages/core` both exit 0; every touched lock entry has version+resolved+integrity; zero unexpected version changes in either lock diff (only intended packages + their transitive helper chains). ## §1.7 Self-discipline check (REQUIRED if PR touches discipline-bearing files) ### §1.7 Forward-check applied This PR introduces no new rule; the forward obligation is that each fix lands at the earliest reachable channel and is executable, not prose: vulnerable versions are excluded structurally by manifest constraints — `package.json:6-10` (overrides block), `packages/core/package.json` overrides, `packages/preset-react-spa/package.json:26` (^6.0.2 floor) — so any future `npm install` cannot silently re-resolve a vulnerable version; regressions fail at install/lock level, before CI. ### §1.7 Backward-check applied Class of this change = dependency-version-constraint updates. Surfaces where the class occurs, each swept: root `package-lock.json` (all 6 target packages patched, no residual vulnerable entries — verified over the full lock, not the diff); `packages/core/package-lock.json` (qs/@babel/core/esbuild patched; contains NO handlebars/js-yaml/markdown-it entries → no overrides needed there); fixture manifests `packages/core/detector/fixtures/hono-drizzle-monorepo/apps/api/package.json:5` + `packages/core/research/fixtures/tier1-single-root/package.json:3` + its stub (bumped in lockstep, internally coherent); other fixture manifests under `packages/core/**/fixtures/` (swept — no other pinned occurrences of affected packages); shipped templates + `install.sh` (grep: zero version pins of affected packages); synth bundle `packages/core/synthesizer/synth-and-wire.bundle.mjs` (not fed by the core esbuild entry — `scripts/build-synth-bundle.sh:17`; `--check` green); install fingerprints/baselines (`tests/install-sh/byte-identical.test.sh` green — unshifted).
artyhoo
added a commit
that referenced
this pull request
Jul 11, 2026
…yte-drift gate, pure-bash delivery layer (python-delivery-v0) (#991) * docs(orchestrator): python-delivery-v0 meta-launch kickoff (launch-table + stage gates) Generated by /pipeline python-delivery-v0 (plan-currency: kickoff on staging #967, no in-flight S1, umbrella open). Orchestration record for the S1-S3 dispatch. Prior-art: skipped — orchestration bookkeeping doc, no new capability * feat(python-starter): curated Python starter ConventionNode[] set (S1 Task 3) Adds packages/core/python-starter/starter-nodes.ts — a curated Python starter node set authored in the frozen neutral IR (ir/types.ts, no field added) and rendered through the existing ADOPTED backends: renderAstgrep (#212, syntax-class default) and renderRuff (#215, TID251/TID253 fast-path). Colocated vitest unit tests (RED-first) assert: grammar-gate pass, getff-* id namespacing (probe-proven: duplicate ids = ast-grep exit 8), render-through-both-backends without error, the probe-proven firing shape, and the datetime caveat — the rendered YAML covers BOTH `datetime.now()` and `datetime.datetime.now()` via two literal-pattern nodes (a single pattern cannot match both; a `$MOD.now()` metavariable over-fires on `foo.now()` — live-verified against @ast-grep/cli@0.44.1). Set content (all severity error): ban datetime.now()/ datetime.datetime.now() calls (flagship P5), ban eval()/os.system() calls (bandit ADOPT-VOCABULARY; ruff refuses FF7001 — ast-grep catch-all), ban datetime.datetime.utcnow (TID251), ban module-level import tensorflow (TID253). SSOT row 217 appended to docs/meta-factory/prior-art-evaluations.md in this same commit (register tail verified: last row was 215; 216 is reserved for the delivery-layer task). vitest.config.ts registers the new python-starter/ include glob. Verified: python-starter 12/12, test:backends 154/154, test:principles 303/303, tsc --noEmit clean. Prior-art: prior-art-evaluations.md#217 (curated Python starter node set — BUILD own content in the neutral IR; ruff has no canonical "recommended" starter preset, bandit's catalog is engine-coupled with no neutral-IR export, Factory plugin #4 is JS/ESLint-coupled — ADOPT-VOCABULARY the ban semantics, author the set ourselves). * feat(python-delivery): commit-time render script + pre-rendered templates + byte-drift gate (S1 T4) Render the curated Python starter node set (packages/core/python-starter/starter-nodes.ts, #217) through the pure ADOPTED backends into static shipped templates under packages/core/templates/python/ (Model A). The renderers stay pure; all fs writes live in packages/core/python-starter/render-python-templates.ts (planPythonTemplates() is pure and is what the drift gate imports). Single-owner lane per rule (coordinator Decision #5), partitioned by node kind — a rule ships in exactly ONE lane so a consumer never gets a duplicate report: - ast-grep lane (call-kind): getff-no-datetime-now, getff-no-datetime-datetime-now, getff-no-eval, getff-no-os-system — one single-doc YAML file per rule under .getff/astgrep-rules/ (idiomatic ast-grep layout; a multi-doc stream fails the repo's own single-document pre-commit yaml.safe_load gate — empirically verified). - ruff lane (attribute/import-kind): getff-no-utcnow (TID251), getff-no-tensorflow-module-import (TID253) — one ruff.toml for the whole lane. Our own sgconfig.yml template (Decision #4, no `ast-grep new` shellout) references the rules dir from the consumer's perspective (ruleDirs: [.getff/astgrep-rules]). Every generated file carries a framework-generated header comment. Byte-drift gate: packages/core/backends/python-templates-drift.test.ts asserts committed templates == fresh render, byte-for-byte, at the pre-push channel (test:backends / hooks/pre-push.ts §5c). Idempotent: re-running the render script produces zero diff. Live-fired end-to-end against the pinned @ast-grep/cli@0.44.1 + ruff==0.15.21 on the exact consumer tree layout (both lanes fire; no rule double-reports). Templates land under a NEW packages/core/templates/python/ dir NOT in install.sh's enumerated copy-list — no install-fingerprint / shipped-doc / principle-test surface is touched. Prior-art: prior-art-evaluations.md#212 (ast-grep render backend, ADOPT) and prior-art-evaluations.md#215 (ruff fast-path render backend, ADOPT) — this commit renders the #217 curated node set through the already-ADOPTED backends; no new render target, the emission verdicts stand. * feat(python-delivery): pure-bash delivery layer + augment-first collision policy + tmp-dir tests (S1 T5) setup.d/45-python.sh ships the pre-rendered Python lint bundle (ast-grep rules + sgconfig.yml + ruff config, S1 Task 4) into a consumer Python repo with an augment-first collision policy — merge into what the consumer authored, never silently clobber. INERT on the npm flow (gated on GETFF_TOOLCHAIN=python; S2 wires the ./setup python entry) — install.sh:564 auto-sources it as a guarded no-op, so byte-identical.test.sh stays 8/8. Collision matrix (probe-decided, .superpowers/sdd/task-2-report.md): - fresh dir -> whole-file copy - sgconfig.yml exists -> structural merge into the block-list ruleDirs (idempotent); unproven shapes (flow-list / multi-key) REFUSE-LOUDLY (a naive second ruleDirs: key = duplicate-field exit 8; a clever-but- unsafe merge is a STOP-line violation) - ruff.toml exists -> REFUSE (a sibling ruff.toml wins entirely + silently disables theirs); ship getff-ruff.toml + `extend` instructions (scalar caveat surfaced if they already use extend) - pyproject [tool.ruff] -> REFUSE (a sibling ruff.toml SILENTLY overrides [tool.ruff]); ship getff-ruff.toml + [tool.ruff.lint] merge steps - re-run -> delivered config artefacts byte-identical (idempotent) Every degrade path is printed AND appended to <consumer>/.getff-python-install.log. A pre-existing .prettierignore gets `.getff/` appended idempotently; none is created. tests/install-sh/python-delivery.test.sh covers every cell + npm-inertness/activation as first-class fixtures (RED-before-GREEN on the merge/refuse logic), plus GATED live-fire: all 4 shipped ast-grep rules + both ruff TID bans fire RED on planted violations (pinned @ast-grep/cli@0.44.1 + ruff==0.15.21; SKIP when unobtainable, like cargo firing.test.ts). Wired into audit-self.yml (meta-all-wired). refresh-covers-full-delivery.test.sh made lane-aware — the Python lane is inert on npm and has its own S2 refresh semantics, out of the npm-refresh-parity gate's population (same rationale as its skill/merge/yq exclusions). SSOT row 216 appended (delivery-mechanism BUILD verdict). Prior-art: prior-art-evaluations.md#216 (thin pure-bash delivery writer — BUILD; no headless tool copies a pre-rendered multi-tool lint bundle into an existing repo with augment-first collision. ADAPT the skip/version-stamp concepts from #124/#125, REFERENCE the `ast-grep new project` #212/#185 scaffold precedent; reuses install.sh copy_safe/merge machinery, zero new deps). * fix(python-delivery): sgconfig idempotency survives trailing-comment edits + .ruff.toml fixture + empty-array guard Review-round-1 findings addressed (commit 9e9b5bac9, setup.d/45-python.sh + tests): - Important: _py_sgconfig_merge's idempotency grep required an exact-match line, so a consumer-added trailing comment on our entry (`- .getff/astgrep-rules # our rules`) was not recognised as already-present — a re-run inserted a DUPLICATE entry, tripping ast-grep exit 8 on the consumer's next scan. Fixed by stripping trailing #-comments before the compare (same shape as the existing rest="${rest%%#*}" ruleDirs: value check two lines away), bash 3.2 compatible. TDD: added a failing cell-(ii) fixture first (RED: 2 entries instead of 1), watched it fail against the unfixed code, then fixed and watched it pass. - Important: setup.d/45-python.sh:153's `.ruff.toml` (dotfile) collision branch had no fixture. Added cell-(iii-dotfile): consumer has .ruff.toml only → layer REFUSEs loudly, ships getff-ruff.toml, prints extend instructions, logs the refusal. Passed immediately (branch already existed and worked). - Minor: tests/install-sh/refresh-covers-full-delivery.test.sh's NPM_LANE_LAYERS array expansion under `set -u` would crash on bash 3.2 if the array were ever empty. Added the repo-precedent length guard (setup.d/lib.sh:281-283 shape) before expansion. Prior-art: skipped — review-fix round, no new capability --------- Co-authored-by: t <t@t.co>
artyhoo
added a commit
that referenced
this pull request
Jul 13, 2026
…e shared ConventionNode core (#1005) * feat(live-generation): S1 Inc1 — neutral live-research → ConventionNode bridge + python Tier-0 keys The one shared BUILD of the live-generation umbrella (research-patch §0 Plane 3): a thin, stack-neutral projection «a researched practice → a ConventionNode (frozen IR)» that python (this stage) and rust (LG-S3) both reuse. It authors ONE neutral node from ONE researched practice and hands it to the existing pure renderAstgrep backend — it is NOT a pipeline, does not render to disk, and touches no network. Bridge (packages/core/synthesizer/research-to-node.ts): - Defines its OWN input interface (AstgrepResearchedPractice — GenerateCandidate-shaped + the frozen-IR `kind:'call'|'attribute'|'import'` discriminator the backend requires; no existing type carries {kind,pattern}). Only the OUTPUT ConventionNode is frozen — no IR field added. - Two honesty lines: (1) MAJOR-1 degrade-not-inert (§Qb) — a practice that does not reduce to a single literal call/attribute/import ban is dropped to a research-only finding BEFORE node construction, never an inert node; (2) the bridge validates provenance ITSELF (validateProvenance, Tier-0 default; tiered when a ResolveCtx is supplied) — the grammar gate does not check the provenance host, so an untrusted source is a research-only finding, never a trusted node. Python Tier-0 allowlist keys (packages/core/research/allowlist.ts — DATA, the `#allowlist-as-code-not-data` discipline, parallel to how react-native/expo were added): - python.official → docs.python.org, peps.python.org - pyyaml → pyyaml.org (the getff-no-yaml-load flagship's security-guidance source) Tests (research-to-node.test.ts, all committed fixtures — $0, never a live MCP call): AC1 getff-no-yaml-load → valid node (grammar gate passes + provenance resolves); AC2 node → renderAstgrep yields rule.pattern "yaml.load($$$ARGS)"; AC3 mutable-default-arg / bare-except → research-only, no node/rule (non-vacuous: with the MAJOR-1 filter disabled the inexpressible practice emits an inert node → the assertion goes RED — RED-before-GREEN verified); AC4 expressible practice with a non-Tier-0 host → host-tier reject (FF2006), NOT an unknown-key/schema failure; no-provenance is fail-closed. Suites green: test:principles 311, test:backends 171, test:composition 46, research 175, to-node byte-locks 19, bridge 10; tsc --noEmit clean. Prior-art: prior-art-evaluations.md#219 (stack-agnostic autogeneration core — BUILD thin, composed over shipped IR + backends + research/trust core; no upstream neutral-multi-backend generator, ast-grep/ruff/antfu confirmed negative 2026-07-11) and prior-art-evaluations.md#218 (LintConfig ADOPT-VOCABULARY coverage-classification + REFERENCE doc->config precedent). Prior-art: prior-art-evaluations.md#183 (rule-research bridge, the shipped JS reference adapter this umbrella generalizes to the neutral ConventionNode plane) and #212/#215 (astgrep/ruff render targets, ADOPT — reused verbatim for the python adapter). * fix(live-generation): S1 Inc1 review — drop untested tiered provenance seam + cover gate-failed + kind-drift guard Review round 1 on commit 91d5332 (the neutral research→ConventionNode bridge): FIX 1 (drop broken/untested tiered seam): remove ResolveCtx/ResearchToNodeOptions param+type, the resolveCtx provenance branch, and the tiered validateProvenanceTiered/resolveAllowedSources imports it used. The Tier-1 path was structurally unreachable (no package field on AstgrepResearchedPractice) AND had zero test coverage — YAGNI + a T20 unverified-code-path risk. The bridge keeps ONLY the Tier-0 validateProvenance path the ACs cover; the Tier-1 python adapter is DEFERRED to LG-S4/rust per research-patch §Qc, where it lands with a package field + Tier-1-reachable tests. Doc-comments corrected: the tiered-seam mentions removed; with allowlist-resolver.ts no longer directly imported the "same purity contract as the renderers" claim is now accurate. FIX 2 (cover the third degrade path): add gate-failed coverage — a degenerate-pair practice (expressible + valid Tier-0 provenance, but examples.bad === examples.good) trips the grammar gate's FF6001 on the built node, asserting status research-only + reason gate-failed. A non-vacuity companion test shows the same practice with distinct examples becomes a node, isolating the degenerate pair as the cause. FIX 3 (kind-drift guard, test-only): export VALID_KINDS from render-astgrep.ts (clean export, no behavior change) and assert EXPRESSIBLE_KINDS set-equals it, so a future kind added to the bridge but not the renderer (node builds then FF7002-refuses) fails at assert time. research-to-node.test.ts: 10 -> 13 tests. test:principles/backends/composition + tsc green. Prior-art: skipped — INC-1 review fixes (drop unused/broken tiered seam + add gate-failed + drift coverage), no new capability * feat(live-generation): S1 Inc2 — python Model A′ render driver + committed getff-researched-no-yaml-load artifact + firing proof The python adapter's author + session-side render (Model A′) half. A committed researched-practice record for the flagship getff-researched-no-yaml-load rule is routed through the INC-1 bridge (researchedPracticeToNode) → renderAstgrep by a new session-side driver, and BOTH the input record and the rendered ast-grep artifact are committed (Model A′ pre-render, §Qa — the consumer install path stays Node-free). - synthesizer/render-researched-astgrep.ts — the driver: pure planResearchedAstgrep / planFromCommittedRecords (compose bridge + pure renderer), impure writeResearchedAstgrep + a --check drift CLI. Renderers stay pure; all fs writes live in the driver (mirrors render-python-templates.ts plan-vs-write and cargo write-clippy.ts vs render-clippy.ts). - synthesizer/fixtures/live-generation/ — the committed record (.practice.json, real Tier-0 `pyyaml` provenance from INC-1), the rendered artifact (firing/rules/*.yml), and RED/CLEAN firing fixtures sharing one ../rules dir so the SAME committed bytes are drift-gated + fired. - backends/astgrep/live-generation-research.test.ts — AC1 record→node, AC2 Model-A byte-drift gate (committed === renderAstgrep([node]), with a paired-negative teeth check), AC3 live-fire via the EXISTING firing-runner harness against pinned ast-grep@0.44.1 (RED on yaml.load / clean on yaml.safe_load), AC4 MAJOR-1 degrade-not-inert through the driver. Home = backends/ so CI's test:backends fires it with the installed pinned binary. - rule id namespaced getff-researched-* (§Qd) so a delivered researched rule never collides with a starter getff-*. call-kind → ast-grep lane ONLY (no ruff render, python-delivery-v0 decision #5). STOP-lines honored: frozen IR (no new ConventionNode field); render-astgrep.ts behavior untouched; NO render-from-research in CI (CI only drift-checks + fires the committed artifact — $0, principle 17 / no-paid-llm-in-ci). Delivery to a scratch consumer + $0 e2e RED is INC-3, out of scope here. Prior-art: prior-art-evaluations.md#219 (stack-agnostic autogeneration core — this is the "session-side render + firing artifact" residue: committed researched practice → INC-1 bridge → renderAstgrep → committed ast-grep artifact; #219 landed in INC-1, cited not re-added) and #212 (ast-grep render target, ADOPT — reused verbatim). * fix(live-generation): S1 Inc2 review — real drift-teeth test + dup-entryId loud guard + docstring Replace the vacuous String.replace/not.toBe 'teeth' test (never called any drift code — attention-is-not-a-mechanism/#discipline-theatre) with two real ones: mutate the committed artifact on disk, run checkResearchedAstgrepDrift(), assert byte-mismatch / missing, restore verbatim bytes in finally (tree left byte-identical). Add a loud dup-entryId/path guard to planResearchedAstgrep (writeResearchedAstgrep would else silently clobber the first), mirroring planPythonTemplates' lane guard + a covering test. Fix planFromCommittedRecords JSDoc PURE -> PURE (read-only fs). Prior-art: skipped — INC-2 review fixes (real drift-teeth test + dup-entryId loud guard + docstring), no new capability * feat(live-generation): S1 Inc3 — deliver researched rule to a scratch consumer + flagship RED proof The LG-S1 headline "live generation WORKS for python": the INC-2 committed researched rule (getff-researched-no-yaml-load) is delivered to a FRESH mkdtemp consumer through the python-delivery-v0 setup.d/45-python.sh augment-first seam — reused VERBATIM via its PY_TEMPLATE_DIR env override (zero seam edit) — and then FIRES RED via the pinned @ast-grep/cli@0.44.1: reports the ruleId + exit 1 on a planted yaml.load(raw), CLEAN (exit 0, zero findings) on yaml.safe_load(raw). - AC1 (always-on): the researched rule joins the consumer's single ruleDirs [.getff/astgrep-rules] additively, byte-identical to the INC-2 artifact; second run idempotent; STOP-line — the rule is NEVER baked into the shipped templates/python starter set (Model A′ per-consumer, §Qe genuinely-researched-not-starter). - AC2 (skipIf(!toolPresent)): fireContract (firing-runner.ts, NOT the npx arm) asserts the delivered rule fires RED; a non-vacuity test delivers WITHOUT it and fires the same fixture → not reported (the RED is delivery-gated, not ambient). - AC3 $0: committed fixtures only, no paid MCP/LLM; lands in test:backends where audit-self.yml installs the free pinned ast-grep binary. - AC4: 11 install baselines byte-identical (PY_TEMPLATE_DIR delivery touches nothing shipped) — no regen. Home backends/astgrep/ mirrors the INC-2 sibling live-generation-research.test.ts: test:backends is the only CI suite with the pinned ast-grep on PATH. Prior-art: skipped — test-only: exercises the existing python-delivery-v0 seam (setup.d/45-python.sh, unedited) + the existing astgrep firing-runner harness + the committed INC-2 artifact; no new capability/dependency/module (flagged only by the >=80-LOC new-file heuristic). * docs(live-generation): S1 census — expressibility research-patch (OWNER-FORK-1 data) Records the LG-S1 sub-deliverable 7 census: 15 real python conventions classified by frozen-IR expressibility with real ast-grep@0.44.1 firing (flat 40% / flat+relational 93.3%; require-via-ban 3/3 positives). DATA-only OWNER-FORK-1 record; the unfreeze decision is a separate MT-plane umbrella. Prior-art: skipped — docs-only OWNER-FORK-1 census data (research-patch), no new capability/dependency/module * chore(live-generation): S1 — regen synth-and-wire bundle for the python Tier-0 allowlist keys Byte-consequence of INC-1's allowlist.ts python Tier-0 keys (research/load.ts imports allowlist.ts → bundled transitively via synth-and-wire). The increments touched allowlist.ts but did not rebuild the bundle; pre-push synth-bundle drift gate caught it. Diff is exactly python.official + pyyaml, --check now in-sync. Prior-art: skipped — build-artifact regen (byte-derived from the reviewed allowlist.ts change), no new capability/dependency/module --------- Co-authored-by: t <t@t.co>
7 tasks
This was referenced Jul 30, 2026
Merged
artyhoo
pushed a commit
that referenced
this pull request
Aug 7, 2026
…check, surface the channel disagreement Round 2 confirmed all six round-1 findings closed and re-derived every §8 figure independently, then found two MAJORs the addendum had not noticed about its own effect on the rest of the file. MAJOR 1 — the §1.7 backward-check asserted SWEPT-CLEAN using figures this same commit restates. Both verdicts re-adjudicated in place rather than left standing: - ADR-3: the "inside ADR-3's stated band" clause was wrong when written — the band is 29-39% and both measurements (27.8% / ~21%) fall BELOW it; under §8.1's conversion the same share moves to ~47%, outside on the high side. Now GAP-FOUND, direction unresolved pending #4. - the spec's P14 row: "the row's arithmetic holds" is true only under the 4 B/t constant it was computed with, since §8.1 restates the same seat at 51.7%. Now HOLDS-CONDITIONALLY on #4B. MAJOR 2 — one seat, two irreconcilable harness figures, previously unflagged. By difference the main seat's remainder is 69,300 of 89,019; /context's categories matching row 5's own definition sum to 28.8k for that SAME session, and neither 28.8k nor 86.9k (adding deferred schemas back) reaches 69,300. The totals disagree the same way: 58.2k resident vs 89,019 first-turn billed, gap ~30.8k. New §8.5 states the disagreement, offers the dispatch-prompt hypothesis explicitly as unmeasured (§0 defines the channel as "resident head PLUS its dispatch prompt", and rows 1-4 never subtract it; this session opened with /orchestrator, which injects a whole SKILL.md body), and draws the consequence that matters: by-difference systematically OVERSTATES the remainder, because anything it cannot attribute to rows 1-4 lands in row 5 by construction. Raised as DECISION-NEEDED #5 with three options including "measure the gap directly". Not resolved here. MINORs: - §4 was the only section the revision sweep had skipped. R1 now carries a PERFORMED block (the paste happened; two of four rows closed, not four; S-D′ no longer has to park). R5's conclusion is REVERSED with its reasoning shown — its "next lever is harness-side" is contradicted by memory files being 50.5% of the resident head and repo-owned. - rows 5c/5e now carry the seat annotation: orchestrator MAIN seat, n=1, not the 62,340-tok subagent seat the table is sized against, with an explicit do-not-sum-against-row-5. - The headline now warns that both its percentages are contested, naming #4 and #5. Count-claims re-swept: 14 table rows, exactly 2 carrying the literal UNMEASURED marker. Prior-art: skipped — review-absorption edit on an existing research patch, no new capability
artyhoo
pushed a commit
that referenced
this pull request
Aug 7, 2026
… the 600-line gate Round 3 confirmed round-2's MAJOR #2 (channel disagreement) and MINOR #4 (seat annotations) fully discharged, and re-derived every §8 figure independently. It then caught the replacement figures themselves. MAJOR — the ADR-3 re-verdict swapped one unsupported number for another: `29,464 / 62,340 ≈ 47%` divides a MAIN-seat /context numerator by the SUBAGENT-seat by-difference denominator — exactly the cross-seat, cross-channel mix this same commit forbids at rows 5c/5e and that §8.5 declares irreconcilable. Restated within one channel: 17,363 × (4/2.6187) = 26,522 = 42.5% of the 62,340-tok seat, or ~26.5% against ADR-3's own ~100k denominator. Both readings put the repo-owned share BELOW the 29-39% band, not above it, so the verdict is now "GAP-FOUND — measured low, consistently across the conversion change" instead of "direction unresolved". MINORs: - §8.1 gave "two reasons, both binding" for not reconverting §2; one was FALSE. Concatenating the five files the ratio was measured on gives 69,453 B and row 1's published 17,363 est-tok is exactly 69,452 B / 4 — the same population, byte for byte. The claim is withdrawn in place and the surviving reason (re-derivation is beyond an addendum) is named as the only one. An unverified escape clause is a stronger shield than the correction it blocks, and this one was steering DECISION-NEEDED #4. - DECISION-NEEDED #5 Option A's "wrong by roughly 2.4x" over-extended: 2.41x is the main-seat ABSOLUTE; the share moves 77.8% -> 49.5%, i.e. 1.57x, and the subagent-seat 68.4% is untouched because /context cannot run inside a subagent. - §8.2 called the whole 29.4k memory block repo-owned; 2,764 of it is host-side (~/.claude CLAUDE.md 964 + MEMORY.md 1,800 = §2 rows 2 and 3). Repo-owned is 26,700 = 45.9% of the head. - The §4 sweep had reached R1 and R5 but not R4, whose premise the paste contradicts: R4 rests on the harness truncating the skills listing "to a ~2k budget", while /context measures the injected block at 8.9k — essentially the un-truncated source-side ~9.1k. Surfaced for S-I, not re-derived here. R4's "129 SKILL.md files" also carries no reproducing command and a recount gives 112, so the population is marked UNVERIFIED. Structural: absorbing the above pushed the patch to 602 lines, over the repo's 600-line markdown gate. Trimming to 599 would be gaming the gate, so §8 is split into a companion patch, 2026-08-07-s-h-p14-context-addendum.md, with §8.x numbering preserved so every cross-reference already written stays valid. Parent 435 lines, addendum 196. Prior-art: skipped — review-absorption edit plus a size-driven split of an existing research patch, no new capability
artyhoo
pushed a commit
that referenced
this pull request
Aug 7, 2026
…them a fourth time Round 5 found 2 MAJOR, both again in the previous round's replacement figures. That is four consecutive rounds where a hand-revised quantitative claim was itself defective, so this round changes method: the unsupportable claims are withdrawn rather than corrected again. MAJOR — the ADR-3 verdict was denominator-SELECTED, not measured. 26,700 has four defensible denominators and they disagree in direction: 29.99% of this seat's own 89,019 first-turn total (INSIDE the 29-39% band), 26.6% of the 60-session median (below), 45.9% of the /context resident head (above), 42.8% of the subagent seat (above). Rounds 3-5 each picked one and each pick was defective — cross-seat, then cross-denominator, then ratio-transferred-across-populations. The verdict is now WITHDRAWN with all four denominators tabled and no verdict issued, and the choice raised as DECISION-NEEDED #6 (which cannot be settled independently of #5, since the options differ precisely by the ~30.8k dispatch-prompt gap #5 records). MAJOR — the "74 listed entries / 112 files = 66%" corroborating channel is WITHDRAWN entirely. The numerator is provably not a subset of the denominator: the two largest listed entries in the capture, dataviz (~380) and claude-api (~360), have no SKILL.md anywhere, as do >=14 other built-ins. The denominator is an unfiltered find carrying marketplace/cache duplicates, vendored node_modules files, worktree copies, packages/core fixtures and uninstalled catalogue rows. A ratio across two different sets measures nothing; publishing it would be the estimate-dressed- as-measurement T-SH-A forbids. MINORs: the "~57% of source" precision is withdrawn to direction-only — it swings 56% to 87% across the four conversion constants in play, and the SKILL.md corpus is itself multi-byte-heavy (six skills carry Russian descriptions), so no constant is defensible for it without measuring that corpus. The 112 recount is no longer offered as a correction: publishing the command is necessary but not sufficient, since the command must already exclude what the claim is not about. measure-always-on.sh's "21-28%" gained the re-adjudication marker every sibling surface had. The §1.7 note previously NAMED T21 while committing it. It now states plainly that this round's sweep was list-driven too, that its hunks map one-to-one onto round 5's findings, and that the class-driven counter T21 prescribes is what the five cold audit rounds have been doing while the author-side sweep never became class-driven. It also records the second method finding: three attempts to repair one comparison failed because the comparison had four denominators, and the correct response was withdrawal. Class sweep applied to the withdrawal itself: every site carrying a listing share was found by grep and corrected, not only the one the audit named — the §7 S-I re-adjudication repeated the withdrawn 57%/66% pair and now reads direction-only. Prior-art: skipped — review-absorption edit on existing research patches, no new capability
artyhoo
pushed a commit
that referenced
this pull request
Aug 7, 2026
…ate ranges, never magnitude words Round 6 confirmed the round-5 withdrawal is complete (57%/66% survive nowhere; 74/112 only inside their own WITHDRAWN notices; no third site) and re-derived all four tabled shares as correct. It then found three MAJORs, all again in this round's own replacement wording. MAJOR — withdrawing "~57% of source" to "a minority of source" INVERTED the claim. Under every constant the same note lists, the injected 8.9k is 56.4% / 56.8% / 72.0% / 86.7% of source — a majority — and 51.4% against the pre-S-I byte count. A magnitude word is not a weaker form of a number, it is a different claim. Both sites now carry the explicit range and NO magnitude word; the withdrawal rule is stated so the next editor does not substitute another adjective. MAJOR — the new measure-always-on.sh re-adjudication claimed the measured 26,700 supersedes the "21-28%" pair. Wrong on the NUMERATOR, not the denominator: 26,700 is the pre-S-G five-file set (pinned byte-for-byte in §8.1) while the "~21%" member is the post-S-G set. No denominator choice repairs a numerator mismatch, so no restatement is offered at all — the bound is unverified here and both the surface and the post-S-G measurement stay S-E's. MAJOR — "Options A/B and C differ precisely by the ~30.8k gap" holds only for A (89,019 − 58,200 = 30,819). B differs by 42,329 and is a 60-session median set against a gap measured on one session, so B compounds #5 with a population change rather than restating it. Corrected in place. MINORs: the "six skills carry Russian descriptions" clause is DROPPED rather than corrected — two greps disagreed (6 vs a repo count polluted by node_modules), and the sentence two lines above faults another figure for lacking a reproducing command, so publishing an unverifiable one there was the same defect. "#6 below" pointed above. DECISION-NEEDED #6 is now propagated to every enumeration that had stopped at #5: the §2 headline warning, R5's REVERSED note (which quotes 45.9% — one of #6's four tabled options, now labelled as such), the §8 pointer, the addendum header and its §1.7 obligation count. The §1.7 note also records that this round's two records disagreed about whether the sweep found an unnamed site: the commit message was right, the paragraph was wrong. The S-I re-adjudication was found by the author's own class grep. Honest summary now stated: list-driven for five rounds, class-driven for exactly one item. Prior-art: skipped — review-absorption edit on existing research patches, no new capability
artyhoo
pushed a commit
that referenced
this pull request
Aug 7, 2026
…ad of restating it an eighth time Seven cold rounds, seven REVISEs, and rounds 4-7 each found the MAJOR in the PREVIOUS round's own replacement wording. The class never changed: deriving a quantity across mismatched populations, denominators or conversion constants. This round stops deriving rather than deriving better. MAJOR (round 7) — the injected-vs-source share published last round has exactly the defect the adjacent paragraph withdraws another channel for: its numerator is the harness total for 74 LISTED entries, its denominator a byte sum over 129 SKILL.md FILES, and the same note proves those populations differ (dataviz ~380 and claude-api ~360 are in the numerator and have no SKILL.md at all). All four attempts at that share — a 66% population ratio, a ~57%, a "minority", a 56.4-86.7% range — are now withdrawn together with one stated reason, and NO figure, range or magnitude word replaces them. What survives is the comparison that needs no denominator: 8.9k measured against the spec's ~2k budget. MAJOR (round 7) — this file established last round that 26,700 is the PRE-S-G five-file set, then used that fact in exactly one place while three others kept building on it: §8.2 reading 1 and §8.4 ranked S-D′'s "top-ranked own-able target" from it, and R5 REVERSED overturned a recommendation with it. The dominant file in that measurement, ai-laziness-traps.md (26,387 B), is one S-G already replaced with a digest a quarter its size. So no ranking, no "top lever" and no share of the current head is derived from the snapshot; what it establishes is the narrower and still-useful claim that repo-owned memory files were the largest resident CLASS on the seat measured. R5's reversal is downgraded to SUSPENDED: its premise moved, but its opposite is not established either, and a post-S-G re-measurement is S-E's. MAJOR (round 7) — §8.4 still said "#4 and #5", the site round 6 named live. Now #4/#5/#6, and §6's Forks bullet — which still listed three — records the real inventory: six forks, five open. MAJOR (round 7) — the §1.7 note asserted the §7 S-I site "was found by the author's own class grep, not by any review naming it". False: round 6's watch-list names that exact line. The claim is retracted in place, and the note now states plainly that the author-side sweep never became class-driven in any round. MINORs: "no magnitude word is used here" was false of its own sentence; the §8 pointer omitted §8.6; "five rounds running" and "round 5's findings" were inherited prose that silently re-pointed to a different commit. Prior-art: skipped — review-absorption edit on existing research patches, no new capability
10 tasks
artyhoo
added a commit
that referenced
this pull request
Aug 7, 2026
…CISION-NEEDED #3 (#1249) * docs(s-h): P14 addendum — operator /context paste answers DECISION-NEEDED #3, and falsifies the 4 B/token convention The operator ran `/context` post-merge and supplied the output, taking Option A of DECISION-NEEDED #3 (§0a). Recorded as a new §8 addendum rather than an in-place rewrite: the measurement history must read "unknown at stage close -> known 2026-08-07", not as though the split had been available all along. §0a is kept verbatim, annotated ANSWERED. Two findings, in order of consequence: §8.1 — the seed's binding 4 B ~ 1 token conversion is FALSIFIED. Seven files carry both a `wc -c` byte count and a harness-reported token count; aggregate 77,156 B / 29,464 tok = 2.62 B/token. Every 4 B/t figure in this patch and its sibling is low by ~1.53x, and because row 5 (harness remainder) is computed BY DIFFERENCE, the remainder is correspondingly HIGH — a first-order restatement puts it near 52%, not 68.4%. Figures are left as published and the correction is recorded as owed, not made: the row-1 file set is the pre-S-G resident set while the ratio was measured on the current one, so they are not the same population, and re-deriving §2 on a new constant is a re-measurement beyond an addendum. Raised as DECISION-NEEDED #4. §8.2 — the reported percentages sum to 105.6% because the two `(deferred)` rows are counted but NOT resident. The identity confirms it exactly: 334.6k - 276.4k = 58.2k resident, and the non-deferred rows sum to 58.2k. Half the resident head is memory files (29.4k of 58.2k), of which two documents carry a third of everything (repo CLAUDE.md 9.3k + ai-laziness-traps.md 9.8k). ToolSearch deferral withholds 58.1k — almost exactly what the entire resident head costs, which is the number §3's "preserve what already works" lacked. §8.3 — closes TWO of the four `UNMEASURED — channel absent` rows, not four: 5c (MCP tool schemas, 8.4k) and 5e (skills 8.9k + custom-agent listing 1k). 5d stays open (`/context` does not itemise server instructions apart from tool schemas) and row 9 stays open (a different population: "Custom agents" counts registered agent types, not the repo's agents/ directory). Neither was filled from the nearest plausible neighbour — that is T-SH-A working, not a shortfall. Revised partition 14 / 11 / 2 / 1, counted from the table. All count-claims re-swept by class after the edit rather than site-by-site (the W-9 lesson from the round-3 fidelity audit): table recount gives 14 rows and exactly 2 carrying the literal marker; the stage-close claims of "four" are retained as historical and each carries its revision inline. Coverage: n=1, an orchestrator seat in a worktree with five rule files injected; a fresh main-checkout or subagent seat has a different resident set. All figures are the harness's own estimates at its own rounding; no tokenizer was run. Prior-art: skipped — post-merge measurement addendum to an existing research patch, no new capability * fix(s-h): absorb cold-audit REVISE on the P14 addendum MAJOR — §8.2 claimed `ToolSearch` deferral "roughly doubles the usable budget". The snapshot cannot support that: window 1m, free space 665.4k, so making the 58.1k deferred schemas resident moves free space to ~607.3k (-8.7%). What doubles is the resident HEAD (58.2k -> 116.3k). Restated to the measure the snapshot actually bounds; the supported neighbouring claims (58.1k is about the size of the whole head; still the most expensive available regression) are kept. MINORs, all from the same cold seat: - §0a heading was present-tense "five blocks stay unpriced", false after the update -> marked "(as at stage close) … stayed", with the current count (three: 5d, 9, row 8's injected form) stated in the ANSWERED block and again in §7. - "five rule files" contradicted the patch's own table -> four, with the four named and the other three memory files identified. - DECISION-NEEDED #4 Option A pointed at the sibling's "§5/§9"; the sibling has no §9 (it runs §0-§8) -> corrected to its actual 4 B/t sites, §5, §7 and §8. - The 5d basis asserted server instructions "sit inside the system-prompt region"; the capture establishes only that /context does not itemise them apart from tool schemas -> the locational claim is dropped, since asserting a region is the estimate T-SH-A forbids. - rows 1-4 restatement read 30,163, which reproduces from neither derivation route -> 19,719 × (4/2.6187) = 30,120, remainder 62,340 - 30,120 = 32,220, share 51.7%. All count-claims re-swept by class after the edit: table holds 14 rows with exactly 2 carrying the literal UNMEASURED marker; every surviving "five" is either historical-and-marked or refers to the item-4 probe's five files, a different subject. Prior-art: skipped — review-absorption edit on an existing research patch, no new capability * fix(s-h): absorb cold-audit round-2 REVISE — re-verdict the backward-check, surface the channel disagreement Round 2 confirmed all six round-1 findings closed and re-derived every §8 figure independently, then found two MAJORs the addendum had not noticed about its own effect on the rest of the file. MAJOR 1 — the §1.7 backward-check asserted SWEPT-CLEAN using figures this same commit restates. Both verdicts re-adjudicated in place rather than left standing: - ADR-3: the "inside ADR-3's stated band" clause was wrong when written — the band is 29-39% and both measurements (27.8% / ~21%) fall BELOW it; under §8.1's conversion the same share moves to ~47%, outside on the high side. Now GAP-FOUND, direction unresolved pending #4. - the spec's P14 row: "the row's arithmetic holds" is true only under the 4 B/t constant it was computed with, since §8.1 restates the same seat at 51.7%. Now HOLDS-CONDITIONALLY on #4B. MAJOR 2 — one seat, two irreconcilable harness figures, previously unflagged. By difference the main seat's remainder is 69,300 of 89,019; /context's categories matching row 5's own definition sum to 28.8k for that SAME session, and neither 28.8k nor 86.9k (adding deferred schemas back) reaches 69,300. The totals disagree the same way: 58.2k resident vs 89,019 first-turn billed, gap ~30.8k. New §8.5 states the disagreement, offers the dispatch-prompt hypothesis explicitly as unmeasured (§0 defines the channel as "resident head PLUS its dispatch prompt", and rows 1-4 never subtract it; this session opened with /orchestrator, which injects a whole SKILL.md body), and draws the consequence that matters: by-difference systematically OVERSTATES the remainder, because anything it cannot attribute to rows 1-4 lands in row 5 by construction. Raised as DECISION-NEEDED #5 with three options including "measure the gap directly". Not resolved here. MINORs: - §4 was the only section the revision sweep had skipped. R1 now carries a PERFORMED block (the paste happened; two of four rows closed, not four; S-D′ no longer has to park). R5's conclusion is REVERSED with its reasoning shown — its "next lever is harness-side" is contradicted by memory files being 50.5% of the resident head and repo-owned. - rows 5c/5e now carry the seat annotation: orchestrator MAIN seat, n=1, not the 62,340-tok subagent seat the table is sized against, with an explicit do-not-sum-against-row-5. - The headline now warns that both its percentages are contested, naming #4 and #5. Count-claims re-swept: 14 table rows, exactly 2 carrying the literal UNMEASURED marker. Prior-art: skipped — review-absorption edit on an existing research patch, no new capability * fix(s-h): absorb cold-audit round-3 REVISE, and split the addendum at the 600-line gate Round 3 confirmed round-2's MAJOR #2 (channel disagreement) and MINOR #4 (seat annotations) fully discharged, and re-derived every §8 figure independently. It then caught the replacement figures themselves. MAJOR — the ADR-3 re-verdict swapped one unsupported number for another: `29,464 / 62,340 ≈ 47%` divides a MAIN-seat /context numerator by the SUBAGENT-seat by-difference denominator — exactly the cross-seat, cross-channel mix this same commit forbids at rows 5c/5e and that §8.5 declares irreconcilable. Restated within one channel: 17,363 × (4/2.6187) = 26,522 = 42.5% of the 62,340-tok seat, or ~26.5% against ADR-3's own ~100k denominator. Both readings put the repo-owned share BELOW the 29-39% band, not above it, so the verdict is now "GAP-FOUND — measured low, consistently across the conversion change" instead of "direction unresolved". MINORs: - §8.1 gave "two reasons, both binding" for not reconverting §2; one was FALSE. Concatenating the five files the ratio was measured on gives 69,453 B and row 1's published 17,363 est-tok is exactly 69,452 B / 4 — the same population, byte for byte. The claim is withdrawn in place and the surviving reason (re-derivation is beyond an addendum) is named as the only one. An unverified escape clause is a stronger shield than the correction it blocks, and this one was steering DECISION-NEEDED #4. - DECISION-NEEDED #5 Option A's "wrong by roughly 2.4x" over-extended: 2.41x is the main-seat ABSOLUTE; the share moves 77.8% -> 49.5%, i.e. 1.57x, and the subagent-seat 68.4% is untouched because /context cannot run inside a subagent. - §8.2 called the whole 29.4k memory block repo-owned; 2,764 of it is host-side (~/.claude CLAUDE.md 964 + MEMORY.md 1,800 = §2 rows 2 and 3). Repo-owned is 26,700 = 45.9% of the head. - The §4 sweep had reached R1 and R5 but not R4, whose premise the paste contradicts: R4 rests on the harness truncating the skills listing "to a ~2k budget", while /context measures the injected block at 8.9k — essentially the un-truncated source-side ~9.1k. Surfaced for S-I, not re-derived here. R4's "129 SKILL.md files" also carries no reproducing command and a recount gives 112, so the population is marked UNVERIFIED. Structural: absorbing the above pushed the patch to 602 lines, over the repo's 600-line markdown gate. Trimming to 599 would be gaming the gate, so §8 is split into a companion patch, 2026-08-07-s-h-p14-context-addendum.md, with §8.x numbering preserved so every cross-reference already written stays valid. Parent 435 lines, addendum 196. Prior-art: skipped — review-absorption edit plus a size-driven split of an existing research patch, no new capability * docs(s-h): add the §1.7 self-review the split addendum owed (principle 13) The pre-push principle-13 gate correctly rejected the new patch: a research patch must carry an actual §1.7 self-review, not merely name the section. Added Forward + Backward + T15. The backward-check is a real outward sweep, not a restatement of this diff — the change class is "a post-merge artefact that revises figures already published in a merged research patch", and six surfaces are verdicted, of which four are GAP-FOUND and left unedited by ownership: - the sibling p3d-p11 patch shares the falsified 4 B/t constant at its §5/§7/§8, so §8.1 applies to it identically — named in DECISION-NEEDED #4's Option A as required scope; - the token-economy spec's tag convention (the constant under one of its tags is wrong); - ADR-3 (repo-owned share measures below its 29-39% band under BOTH conversions); - the S-A profile patch (closed historical artefact, its authoring session owns it). T15 records the reflexive fact that this file exists only because the parent hit the 600-line markdown gate — a document about document cost split by a size discipline. Prior-art: skipped — self-review section required by principle 13 on an existing patch, no new capability * fix(s-h): absorb cold-audit round-4 REVISE — four MAJORs, all in this round's own replacement figures The split is sound (parent 463, addendum 261, all 43 §8.x cross-references resolve) and the addendum's §1.7 backward-check verified as a real outward sweep. But three of round 3's four replacement figures were themselves defective, plus a new challenge block that reversed a downstream premise on an invalid comparison. MAJOR — "Both readings put the repo-owned share BELOW the 29-39% band" is arithmetically false: 42.5% > 39%. And 42.5% is a share of the 62,340-tok SUBAGENT seat while ADR-3's band is denominated on ~100k, so it is not band-comparable at all. Round 3 replaced a cross-SEAT mix with a cross-DENOMINATOR one. Now stated from the directly measured figure with both traps recorded inline so it is not re-derived wrongly a third time. MAJOR — 26,522 was derived by applying §8.1's SEVEN-file aggregate ratio (2.6187, inflated by the one host-side Russian-text outlier at 3.32 B/t) to row 1's FIVE-file population, while the addendum measures that exact population directly at 26,700 (five-file ratio 2.6012). One commit, two values for one block. The measured figure now supersedes the derivation: 26,700 = 26.7% against ~100k (band-comparable, below the band) and 42.8% of the subagent seat (not comparable). MAJOR — round 3's "29.4k is not repo-owned" fix was applied in §8.2 but not swept: §8.4 (the S-D′-facing ranking section) and §4 R5's REVERSED note both still read "29.4k, 50.5% repo-owned", overstating the own-able block by 2,764 tok at the one site a downstream stage reads. Both fixed to 26,700 = 45.9%. Third site of the same class: "six ASCII-dominant repo files" counted host-side MEMORY.md as a repo file. MAJOR — the R4 CHALLENGED block concluded the skills listing "appears not to be truncated at all", comparing the /context-measured 8.9k against a ~9.1k figure that is a 4 B/t estimate this same commit declares low by 1.53x. In one constant: 41,057 B / 2.6187 = 15,678 tok, so 8.9k is ~57% of source; independently the snapshot lists 74 entries against a 112-file population, ~66%. Both channels say REDUCED. The supported half survives — the ~2k budget premise is wrong by ~4x — and that, not "no truncation", is what is routed to S-I. MINORs: §4 R2's "until then / which R1 would settle" was stale once R1 discharged (now PARTLY SETTLED, with the evidence stated as non-conclusive and the row keeping its UNMEASURED pricing rather than gaining a "0"); §7's S-I-kickoff backward-check verdict was not re-adjudicated although this commit moves that kickoff's premise (now GAP-FOUND, routed not edited); the T3 demand for a reproducing command was applied to the 129 being corrected but not to the 112 correcting it (command now published beside it). The addendum's §1.7 now records the method failure rather than only the rows: four rounds, four sweeps driven by the last review's list, each re-failing on whatever the list omitted — T21 in its own-work form. Prior-art: skipped — review-absorption edit on existing research patches, no new capability * fix(s-h): absorb round-5 REVISE by WITHDRAWING claims, not repairing them a fourth time Round 5 found 2 MAJOR, both again in the previous round's replacement figures. That is four consecutive rounds where a hand-revised quantitative claim was itself defective, so this round changes method: the unsupportable claims are withdrawn rather than corrected again. MAJOR — the ADR-3 verdict was denominator-SELECTED, not measured. 26,700 has four defensible denominators and they disagree in direction: 29.99% of this seat's own 89,019 first-turn total (INSIDE the 29-39% band), 26.6% of the 60-session median (below), 45.9% of the /context resident head (above), 42.8% of the subagent seat (above). Rounds 3-5 each picked one and each pick was defective — cross-seat, then cross-denominator, then ratio-transferred-across-populations. The verdict is now WITHDRAWN with all four denominators tabled and no verdict issued, and the choice raised as DECISION-NEEDED #6 (which cannot be settled independently of #5, since the options differ precisely by the ~30.8k dispatch-prompt gap #5 records). MAJOR — the "74 listed entries / 112 files = 66%" corroborating channel is WITHDRAWN entirely. The numerator is provably not a subset of the denominator: the two largest listed entries in the capture, dataviz (~380) and claude-api (~360), have no SKILL.md anywhere, as do >=14 other built-ins. The denominator is an unfiltered find carrying marketplace/cache duplicates, vendored node_modules files, worktree copies, packages/core fixtures and uninstalled catalogue rows. A ratio across two different sets measures nothing; publishing it would be the estimate-dressed- as-measurement T-SH-A forbids. MINORs: the "~57% of source" precision is withdrawn to direction-only — it swings 56% to 87% across the four conversion constants in play, and the SKILL.md corpus is itself multi-byte-heavy (six skills carry Russian descriptions), so no constant is defensible for it without measuring that corpus. The 112 recount is no longer offered as a correction: publishing the command is necessary but not sufficient, since the command must already exclude what the claim is not about. measure-always-on.sh's "21-28%" gained the re-adjudication marker every sibling surface had. The §1.7 note previously NAMED T21 while committing it. It now states plainly that this round's sweep was list-driven too, that its hunks map one-to-one onto round 5's findings, and that the class-driven counter T21 prescribes is what the five cold audit rounds have been doing while the author-side sweep never became class-driven. It also records the second method finding: three attempts to repair one comparison failed because the comparison had four denominators, and the correct response was withdrawal. Class sweep applied to the withdrawal itself: every site carrying a listing share was found by grep and corrected, not only the one the audit named — the §7 S-I re-adjudication repeated the withdrawn 57%/66% pair and now reads direction-only. Prior-art: skipped — review-absorption edit on existing research patches, no new capability * fix(s-h): absorb round-6 REVISE — the withdrawal inverted a claim; state ranges, never magnitude words Round 6 confirmed the round-5 withdrawal is complete (57%/66% survive nowhere; 74/112 only inside their own WITHDRAWN notices; no third site) and re-derived all four tabled shares as correct. It then found three MAJORs, all again in this round's own replacement wording. MAJOR — withdrawing "~57% of source" to "a minority of source" INVERTED the claim. Under every constant the same note lists, the injected 8.9k is 56.4% / 56.8% / 72.0% / 86.7% of source — a majority — and 51.4% against the pre-S-I byte count. A magnitude word is not a weaker form of a number, it is a different claim. Both sites now carry the explicit range and NO magnitude word; the withdrawal rule is stated so the next editor does not substitute another adjective. MAJOR — the new measure-always-on.sh re-adjudication claimed the measured 26,700 supersedes the "21-28%" pair. Wrong on the NUMERATOR, not the denominator: 26,700 is the pre-S-G five-file set (pinned byte-for-byte in §8.1) while the "~21%" member is the post-S-G set. No denominator choice repairs a numerator mismatch, so no restatement is offered at all — the bound is unverified here and both the surface and the post-S-G measurement stay S-E's. MAJOR — "Options A/B and C differ precisely by the ~30.8k gap" holds only for A (89,019 − 58,200 = 30,819). B differs by 42,329 and is a 60-session median set against a gap measured on one session, so B compounds #5 with a population change rather than restating it. Corrected in place. MINORs: the "six skills carry Russian descriptions" clause is DROPPED rather than corrected — two greps disagreed (6 vs a repo count polluted by node_modules), and the sentence two lines above faults another figure for lacking a reproducing command, so publishing an unverifiable one there was the same defect. "#6 below" pointed above. DECISION-NEEDED #6 is now propagated to every enumeration that had stopped at #5: the §2 headline warning, R5's REVERSED note (which quotes 45.9% — one of #6's four tabled options, now labelled as such), the §8 pointer, the addendum header and its §1.7 obligation count. The §1.7 note also records that this round's two records disagreed about whether the sweep found an unnamed site: the commit message was right, the paragraph was wrong. The S-I re-adjudication was found by the author's own class grep. Honest summary now stated: list-driven for five rounds, class-driven for exactly one item. Prior-art: skipped — review-absorption edit on existing research patches, no new capability * fix(s-h): stop deriving — withdraw every cross-population share instead of restating it an eighth time Seven cold rounds, seven REVISEs, and rounds 4-7 each found the MAJOR in the PREVIOUS round's own replacement wording. The class never changed: deriving a quantity across mismatched populations, denominators or conversion constants. This round stops deriving rather than deriving better. MAJOR (round 7) — the injected-vs-source share published last round has exactly the defect the adjacent paragraph withdraws another channel for: its numerator is the harness total for 74 LISTED entries, its denominator a byte sum over 129 SKILL.md FILES, and the same note proves those populations differ (dataviz ~380 and claude-api ~360 are in the numerator and have no SKILL.md at all). All four attempts at that share — a 66% population ratio, a ~57%, a "minority", a 56.4-86.7% range — are now withdrawn together with one stated reason, and NO figure, range or magnitude word replaces them. What survives is the comparison that needs no denominator: 8.9k measured against the spec's ~2k budget. MAJOR (round 7) — this file established last round that 26,700 is the PRE-S-G five-file set, then used that fact in exactly one place while three others kept building on it: §8.2 reading 1 and §8.4 ranked S-D′'s "top-ranked own-able target" from it, and R5 REVERSED overturned a recommendation with it. The dominant file in that measurement, ai-laziness-traps.md (26,387 B), is one S-G already replaced with a digest a quarter its size. So no ranking, no "top lever" and no share of the current head is derived from the snapshot; what it establishes is the narrower and still-useful claim that repo-owned memory files were the largest resident CLASS on the seat measured. R5's reversal is downgraded to SUSPENDED: its premise moved, but its opposite is not established either, and a post-S-G re-measurement is S-E's. MAJOR (round 7) — §8.4 still said "#4 and #5", the site round 6 named live. Now #4/#5/#6, and §6's Forks bullet — which still listed three — records the real inventory: six forks, five open. MAJOR (round 7) — the §1.7 note asserted the §7 S-I site "was found by the author's own class grep, not by any review naming it". False: round 6's watch-list names that exact line. The claim is retracted in place, and the note now states plainly that the author-side sweep never became class-driven in any round. MINORs: "no magnitude word is used here" was false of its own sentence; the §8 pointer omitted §8.6; "five rounds running" and "round 5's findings" were inherited prose that silently re-pointed to a different commit. Prior-art: skipped — review-absorption edit on existing research patches, no new capability * fix(s-h): absorb round-8 REVISE — narrow the withdrawal to what its basis says, repair the broken substitution Round 8 recorded the first CLEAN on W-5, the cross-population-share criterion that produced the MAJOR in rounds 4, 5, 6 and 7. The remaining findings are a different and narrower class. MAJOR — §8.4 stated its withdrawal broader than the §8.2 reading it cites as basis: §8.2 withdraws shares "of the current head", §8.4 restated that as "every share of it [the pre-S-G set] is withdrawn" — while four surfaces still publish exactly such shares (§8.2's class table, §8.6's four-denominator table and their two parent-side twins) and while holding #6 open, whose entire subject is which share to publish. Narrowed to match: the pre-S-G shares stay valid AS pre-S-G shares and are not withdrawn; what is withdrawn is any share of, or top lever for, the CURRENT set — which is what a subtraction map acts on. #6 is now named as the question of which denominator a pre-S-G share is quoted against. MAJOR — propagating the share-withdrawal into the §7 S-I surface broke the sentence: "the listing is nonetheless reduced to measured at 8.9k injected" left a dangling verb phrase, asserted 8.9k twice, and kept the direction word "reduced" that R4 forbids six lines into its own text. Rewritten to carry R4's own closing position: the budget premise is wrong by ~4x, and NO claim is made about truncation either way. MINORs: §1.7's marker inventory still read "R5 REVERSED" after this round renamed it SUSPENDED; the -20,782 B set cut was attributed entirely to the traps->digest swap, which accounts for -19,684 B (the rest is two other files in the same trim); §8.4 called §8.1's measured B/token aggregate an "identity" alongside §8.2's exact arithmetic one, upgrading a 2.37-3.32 empirical average to an exact relation in the round whose purpose was the opposite; "the file that dominates this measurement" is 9.8k against CLAUDE.md's 9.3k, so it is the largest single file, not a dominant one. Prior-art: skipped — review-absorption edit on existing research patches, no new capability * fix(s-h): absorb round-9 REVISE — propagate the narrowed withdrawal to §1.7, drop the wrong-side share label Round 9 resolved five of round 8's six findings and returned one MAJOR of the same W-17 class at a site the previous commit did not reach, plus one MINOR in the wording it introduced. MAJOR — §8.4 narrowed its withdrawal to "any share of the CURRENT set", but the §1.7 T15 paragraph still carried the pre-round-8 breadth: "(§8.2 reading 1, whose share figures are withdrawn as pre-S-G)". The file therefore issued two incompatible instructions about the same table to the same consumer, and the §1.7 form also dropped the "of the current head" qualifier its cited basis carries (§8.2 reading 1). Restated to match that basis exactly: a pre-S-G measurement from which no share of the current head is derived. Enumerated every withdrawal statement across all three S-H patches (grep -n withdraw → 6 hits: addendum :69, :159, :290, :327; parent :262, :297); this was the sole over-broad survivor — :262 withdraws the injected-vs-source share, :297 withdraws the R5 reversal, both correctly scoped. MINOR — the exemption introduced last round read "remain valid as shares of that pre-S-G set". That is exact for §8.2, whose denominator IS the pre-S-G resident head (58.2k), but inverted for §8.6, where the pre-S-G block (26,700) is the NUMERATOR and the four denominators are seat totals — the relation the same paragraph states correctly two lines later. Replaced with a form true of both: computed from that pre-S-G measurement, each against the denominator its own table names. Both edits are subtractive/narrowing and introduce no figure, ratio or magnitude word — the strategy that first produced a CLEAN on W-5 at round 7. Prior-art: skipped — review-absorption edit on existing research patches, no new capability --------- Co-authored-by: Test <test@example.com>
artyhoo
added a commit
that referenced
this pull request
Aug 7, 2026
…red) + the kickoff it unblocks (#1255) * arch-v2: S-L recalculation stage — the #5-C measurement + the kickoff it unblocks The S-H work shipped three open forks (#4 conversion constant, #5 remainder channel, #6 denominator) whose resolutions all move the same numbers. #5's Option C was a measurement rather than a vote; it is run here, and it changes what the recalculation stage has to do. Measurement (docs/meta-factory/research-patches/2026-08-07-s-l-5c-first-turn-vs-context.md): one seat, `/context` as the first message, then the first billed turn — both halves, same seat, in the required order. Four session-root transcripts in one worktree, all sharing an identical cache_read prefix of 22,367, so the deltas are differences with everything else held byte-constant. The addendum's named falsifier FIRED. The ~30.8k gap was hypothesised to be dispatch-prompt content; measured, the `/orchestrator` injection is 13,523 tok (44% of it), and two bare-prompt seats reproducing 75,496 exactly still show a 16,196-token gap against a `/context`-reported 59.3k with no dispatch prompt present at all. The residual is seat-constant and dominated by harness-injected session-start payload, which also reopens the DIRECTION of the addendum's §8.5 (if `/context` omits genuine recurring seat cost, it under-reports rather than by-difference overstating). Routed to S-L, not decided here. Second, independent falsification of flat-constant conversion: a dense markdown table measured 1.83 B/token, below the 2.37-3.32 spread S-H recorded. Fork #4 = Option A in its per-seat form is re-confirmed, and 2.62 is explicitly not the replacement — it would have mis-priced that block by 43%. S-L kickoff: applies #4 per-seat at every consuming site (BYTES_PER_TOKEN=4 is live, five consumers), designs the #5 re-labelling from scratch, runs the residual decomposition, and re-adjudicates ADR-3's band to close #6. Tier 2, no marker, host-bound. Recorded as a third gate on S-D′, which ranks levers by the P14 price list — a falsified conversion falsifies the ranking. The merged S-H patches are untouched: corrections land as a new patch plus annotations, per the Artifact Ownership Contract. Prior-art: skipped — measurement plus a stage kickoff over existing S-H outputs, no new capability, no dependency and no packages/ file. * arch-v2: record S-L's ordering as an open question, not a third gate Self-correction to the previous commit, caught by running the backward sweep for the class "a new stage is added to a live umbrella" instead of recalling it. That commit rewrote S-D′'s Depends-on cell from the two-gate `S-E + S-H` form to a three-gate `S-E + S-H + S-L`. The sweep found the phrase is load-bearing in eight places outside that cell: umbrella `:237`, `:371` and §3 (which DEFINES "the two-gate form" as a named pattern), four statements in the just-merged s-d-prime/kickoff.md rev 6 (`:1`, `:106`, `:305`, `:355` — the last three saying the two-gate dependency is the ONLY remaining gate), and the spec's "S-D′ after S-E + S-H" at `:410`. Editing one cell to three-gate while those stand contradicts the umbrella's own Ordering statement ("table and prose agree"), and sweeping all eight is a structural change to a named pattern with an owner — out of scope for a PR whose job is to author one kickoff (CLAUDE.md PR strategy). So: the cell returns to two-gate and carries the constraint as an explicit open question; the S-L section states why it is recorded rather than enforced; the promotion is surfaced as DECISION-NEEDED for the operator. The constraint itself is unchanged and still stated in S-L's own kickoff — what changes is that this PR no longer pretends to have decided it. Prior-art: skipped — correction to a coordination-doc row in the same PR, no new capability. * fix(patch): spell the sibling patch's full filename — a leading hyphen crashed the dead-link check The backward-check row abbreviated the second grep-collision file as `-s-a-profile.md`. The CI dead-link step pipes every backticked *.md span into `basename "$ref"`, and GNU coreutils parses a leading `-s` as the --suffix option: `gbasename "-s-a-profile.md"` → "missing operand", exit 1, and the step runs under bash -e, so the whole job went red on a cosmetic abbreviation. Reproduced locally before fixing (gbasename, exit 1) rather than inferred from the log, and a repo-wide `grep -rhoE '`-[^`]*\.md`'` confirms this was the only leading-hyphen backticked .md reference in the tree — introduced by the previous commit, not pre-existing. Fix is the honest one anyway: write 2026-08-01-token-economy-s-a-profile.md in full. The CI script's own fragility (an unguarded operand reaching basename) is a separate concern, surfaced in the PR body rather than fixed here. Prior-art: skipped — one-line filename spelling correction in an unmerged patch, no new capability. * arch-v2: S-L's ordering deadline went LIVE mid-session — S-E merged Merge-forward from staging brought #1237 (S-E) in, and that falsifies a claim this branch made twice: that the "before S-D′" deadline was real but not binding "since S-D′ is blocked on the two-gate S-E + S-H and S-E is unmerged". Both gates are now closed — S-H #1239 at 2026-08-07T00:06Z, S-E #1237 at 2026-08-07T09:39Z — verified with `gh pr view --json state,mergedAt` rather than read off the umbrella prose, which still described the pre-merge state. S-D′ is dispatchable today, so S-L is on the critical path, and a dispatcher reading s-d-prime/kickoff.md:305 would find "the remaining gate ... is the two-gate S-E + S-H dependency alone" satisfied and dispatch against a falsified conversion. The Option A call from the previous commit stands — re-declaring the umbrella's named two-gate form across eight sites is still a structural change with an owner, and still out of scope here. What changes is urgency, not scope: the S-D′ row now carries the both-gates-satisfied warning inline, and the PR's DECISION-NEEDED 1 is a live footgun rather than a hypothetical one. Prior-art: skipped — factual correction of an ordering claim plus its coordination-row surfacing, no new capability. * fix(patch): publish the conversion ratio as 1.835, not the truncated 1.83 13,827 chars / 7,535 tokens = 1.8350. The patch published "1.83", which is a truncation rather than a rounding, and the derived "mis-priced by 43%" figure is computed from the exact value: |2.62 - 1.835| / 1.835 = 43%. A reader recomputing from the published 1.83 gets 43% too, but from a correctly-rounded 1.84 gets 42% — so the published figure and its own derivation could disagree depending on which way the reader rounded. Publishing three decimals removes the ambiguity: 1.835 reproduces both the "below the 2.37-3.32 band" claim and the 43% mispricing exactly. Caught by re-deriving every published figure machine-side rather than re-reading them. Prior-art: skipped — numeric precision correction in an unmerged patch, no new capability. --------- Co-authored-by: Test <test@example.com>
artyhoo
pushed a commit
that referenced
this pull request
Aug 7, 2026
…re table, and a 1.785 printed as 1.835 A cold fidelity audit on the round-1 head returned REVISE with three MAJOR findings. All three were real; two were invisible to the author. Fixed: 1. §4.1 numerator provenance was FALSE. It read "the five repo-owned files with no `paths:` frontmatter" — that predicate selects 11 rules + CLAUDE.md = 124,529 B, not the 48,671 B actually measured. Seven Class-B/C rules carry no `paths:` key yet reach the model by hook, skill-embed or agent channel. "No paths:" is not "always-on". The numerator is now defined by the channel that produced it (/context Memory Files, 5 project-scoped files). 2. §4.2's whole share table was T-SL-B — the trap this stage exists to prevent, published while the patch self-certified compliance with it. The numerator is the post-S-G set (contains ai-laziness-digest.md, absent at f31fd8c); every denominator was measured on a pre-S-G seat. The table is replaced: the only internally-consistent pairing (pre-S-G/pre-S-G) is published, and post-S-G shares now read UNMEASURED — channel absent. This makes the #6 answer stronger, not weaker: ADR-3 cannot be restated as a percentage until a post-S-G seat is measured, which is a result rather than a preference, and it ships with a named falsifier. 3. §1.2 row 1 paired 7,535 tokens (stdout + command block) with 13,450 (stdout alone) and printed 1.835, which computes to 1.785. Same trap, one table earlier. Numerator corrected to 13,829. Also delivers what the audit flagged as routed-instead-of-done: the #5 naming RULE and the #6 operative restatement are now stated as delivered (with falsifiers), leaving only the term assignment and the denominator choice routed to the operator, per the dispatch instruction. Plus the MINORs: six-file spread with a k-of-n coverage predicate (MEMORY.md is host-side and its state at seat time is unrecoverable); 59,300 labelled as /context's reported total, not the resident head (58,200); the grep block marked a digest rather than passed off as literal stdout; the Messages row noted as excluding the 31-cp prompt that arrives after the reading. §6 no longer self-certifies T-SL-B. It records all three trips as an incident table, naming which were caught cold — because a trap the author declares clean while violating it is worth more as evidence than as a checkbox. Prior-art: skipped — corrections to this stage's own unmerged patch after a cold audit; no new dependency, no new packages/ file, no new capability.
artyhoo
added a commit
that referenced
this pull request
Aug 7, 2026
… it, #5/#6 routed (#1263) * arch-v2 S-L: recalculation — fork #4 as a band, the unit defect under it, #5/#6 routed Applies fork #4 = Option A in its per-seat form and runs the §1.3 decomposition. Four results: 1. The conversion had an undefined UNIT. S-H measured bytes, the 5-C census measured codepoints, both labelled "B/token". Re-measured at f31fd8c (the commit the seat actually loaded — the seat pre-dates S-G reaching that worktree), S-H's byte table reproduces exactly, and in codepoints its 3.32 outlier collapses to 2.587, inside the cluster. The unit now binds to the channel and every figure carries its suffix. 2. §1.3's named load-bearing unknown is CLOSED: /context's `Skills 8.9k` IS the skill_listing attachment (69 entries both channels, per-entry sum 8,870). `Custom agents 1k` is the orchestrator-planner entry alone; the six built-in agent descriptions are billed and counted nowhere. `Messages 1.3k` is bounded to exactly one hook inject, never both (UNMEASURED which). 3. /context UNDER-reports: ≥15,258 codepoints of every-seat harness-injected payload are billed and appear in no category. Addendum §8.5's "the gap indicts the by-difference method" inverts. 4. ADR-3's 29-39% band is stale by construction — S-G cut the numerator 69,453 → 48,671 B (reproduced exactly). Post-S-G the set is 18,081-20,469 tok, a range, not a point. scripts/measure-turn-attribution.sh: BYTES_PER_TOKEN=4 → a LO/HI band at all five consumers, each emitting a range with its direction of error. No constant is substituted — a `4` → `2.62` diff is exactly the T-SL-A defect this stage exists to prevent. Also fixes a defect the cold backward sweep found in this stage's OWN first edit: the stream builder used jq `length` (codepoints) for a field reported as "stdout-bytes" and converted through the byte band. With `utf8bytelength` the corpus figure now matches the live `wc -c` probe — 1,759 vs 1,760 and 1,866 vs 1,866 — which falsifies the merged `…-p3d-p11.md:482` account of that "~2% spread" as a trailing newline plus language variant. It was a unit conflation, and it closes. DECISION-NEEDED #5 (which channel keeps "harness remainder"), #6 (ADR-3's denominator) and #7 (T-SH-B corpus drift, +11.1%) are surfaced with recommendations and NOT picked — §3a. Prior-art: skipped — recalculation of existing measurements plus a unit correction in an existing script; no new dependency, no new packages/ file, no new capability. * fix(s-l): cold-audit round 1 — false numerator provenance, a void share table, and a 1.785 printed as 1.835 A cold fidelity audit on the round-1 head returned REVISE with three MAJOR findings. All three were real; two were invisible to the author. Fixed: 1. §4.1 numerator provenance was FALSE. It read "the five repo-owned files with no `paths:` frontmatter" — that predicate selects 11 rules + CLAUDE.md = 124,529 B, not the 48,671 B actually measured. Seven Class-B/C rules carry no `paths:` key yet reach the model by hook, skill-embed or agent channel. "No paths:" is not "always-on". The numerator is now defined by the channel that produced it (/context Memory Files, 5 project-scoped files). 2. §4.2's whole share table was T-SL-B — the trap this stage exists to prevent, published while the patch self-certified compliance with it. The numerator is the post-S-G set (contains ai-laziness-digest.md, absent at f31fd8c); every denominator was measured on a pre-S-G seat. The table is replaced: the only internally-consistent pairing (pre-S-G/pre-S-G) is published, and post-S-G shares now read UNMEASURED — channel absent. This makes the #6 answer stronger, not weaker: ADR-3 cannot be restated as a percentage until a post-S-G seat is measured, which is a result rather than a preference, and it ships with a named falsifier. 3. §1.2 row 1 paired 7,535 tokens (stdout + command block) with 13,450 (stdout alone) and printed 1.835, which computes to 1.785. Same trap, one table earlier. Numerator corrected to 13,829. Also delivers what the audit flagged as routed-instead-of-done: the #5 naming RULE and the #6 operative restatement are now stated as delivered (with falsifiers), leaving only the term assignment and the denominator choice routed to the operator, per the dispatch instruction. Plus the MINORs: six-file spread with a k-of-n coverage predicate (MEMORY.md is host-side and its state at seat time is unrecoverable); 59,300 labelled as /context's reported total, not the resident head (58,200); the grep block marked a digest rather than passed off as literal stdout; the Messages row noted as excluding the 31-cp prompt that arrives after the reading. §6 no longer self-certifies T-SL-B. It records all three trips as an incident table, naming which were caught cold — because a trap the author declares clean while violating it is worth more as evidence than as a checkbox. Prior-art: skipped — corrections to this stage's own unmerged patch after a cold audit; no new dependency, no new packages/ file, no new capability. * fix(s-l): cold-audit round 2 MINORs — a spec enumeration stronger than the measurement, and four traceability slips Round 2 returned GO (W-1..W-6 clean). These are its five MINORs, all cheap and all correctness/traceability rather than substance: - spec §1.5 annotation said "both hook injects" are counted nowhere, while the patch's own §2.3 concludes /context's `Messages` counts exactly ONE of them. The spec is S-D′'s consumed instrument, so an enumeration there that overstates what was measured is the one MINOR worth fixing on its own merits. The >=15,258 figure it accompanies was already correct. - §2.2's console block was a hand-composed digest wearing `$` prompts. §1.4 got that label in round 1; §2.2 did not. Both figures re-verified (n=69, sum 8,870). - Three `(§1.5)` cross-references pointed at the corpus-drift section after the 641->596 line compression renumbered the band treatment to §1.6. - 13,829 vs the 5-C patch's printed 13,827 for the same delta, previously unremarked: 5-C also nets the seats' 4-char prompt difference and 2-char hook differences. Both round to 1.835. - Supersede anchor cited addendum :60-63; the quoted sentence is at :55-57. Prior-art: skipped — traceability corrections to this stage's own unmerged patch plus one spec wording fix; no new dependency, no new packages/ file, no new capability. * fix(s-l): cold-audit round 3 MINORs — name both seats at the pairing, and stop normalising a merged sign slip Round 3 returned GO (W-1..W-9 clean). Its two MINORs, neither changing a figure: - §3.1's counted/uncounted accounting paired census rows from seat 384ada17 with /context categories from seat 45489086 without naming either — while §3.2's own naming rule demands channel, unit and seat. Both are now named at the pairing, and the reason it is legitimate is stated as a CHECK rather than an assumption: skill_listing measures 26,696 cp identically on both seats, so the payload is seat-invariant across the pair. §2.3 gets the same treatment. - §1.4 rendered the `…-p3d-p11.md:536` site in backticks as `wc -c ÷ 4 B/tok`, but the merged source prints `×`. Division is the correct intent (multiplying bytes by B/token is dimensionally nonsense) and the stated direction only follows under it — but backticks signal verbatim, so quoting the source's own sign and naming the correction is the honest form. Silently normalising another patch's slip is the small version of what this stage exists to catch. Prior-art: skipped — citation-accuracy corrections to this stage's own unmerged patch; no new dependency, no new packages/ file, no new capability. --------- Co-authored-by: Test <test@example.com>
artyhoo
added a commit
that referenced
this pull request
Aug 7, 2026
…are term, name the denominator, accept the drift (#1266) ## What Records the operator's verdicts on the three DECISION-NEEDEDs that S-L (PR #1263, squash `a9fc0af959`) routed, and applies the two that bind a site. | fork | verdict | effect | |---|---|---| | **#5** — which channel keeps «harness remainder» | **A — retire the bare term** | two explicit names; re-labelling only | | **#6** — which denominator ADR-3 names | **A — the seat first-turn total** | names the denominator; produces **no** number | | **#7** — T-SH-B corpus drift +11.1% | **accept as accretion** | nothing — S-H's aggregates stand | **No published number changes value.** Three files: a new patch recording the verdicts, the ADR-3 edit they bind, and two in-cell kickoff updates. ## Why these picks - **#5 = A** on asymmetry of error: the two channels differ by a **non-constant** residual (16,196 tok vs ~17.3k), so the bare term does not denote one quantity. A stays correct whichever way the rule's own falsifier resolves; B would be substantively wrong if the residual stays variable. C was dominated — it re-bases onto the `/context` channel S-L measured **incomplete** (≥15,258 cp billed and uncategorised). - **#6 = A** on the umbrella's own hard-won discipline: *a share's numerator must be a provable subset of its denominator* — only A satisfies it (same seat class, n=2, 35.4% on the pre-S-G pairing). B spans seats with different repo rule-sets; C denominates on the incomplete channel. - **#7 = accept**: drift is **upward** (+11.1%), ordinary accretion — the opposite class from the −27% retention event T-SH-B was written against. All S-L measurements are within-seat, so corpus size does not enter them. ## The distinction that made the #5 sweep non-mechanical The term is retired **as a quantity label**, not **as an artifact title**. The umbrella's three uses (`:102`, `:273`, `:309`) name the P14 *deliverable* — which is also the merged patch's filename — so renaming them would break provenance, not improve labelling. Exactly one live site used the term for a quantity, and it is fixed. ## Also carried: the stale share the spec still held ADR-3 still read «29-39%» — S-G moved the numerator (69,453 → 48,671 B) while every denominator in hand was pre-S-G, making it a cross-population division. PR #1265 swept the three sibling copies but deliberately left this one, reserved for verdict #6. Now aligned with them. ## Surfaced, not built The naming rule's only enforcement is authoring discipline — `#hope-as-gate` by `.claude/rules/attention-is-not-a-mechanism.md:29`. Promoting it to a channel is a capability commit and out of scope for a verdict-recording PR; flagged for the operator, not undertaken. ## Provenance n/a ## Review findings n/a ## Fidelity verdict FIDELITY: skipped — non-stage PR: it records operator verdicts on the already-merged S-L DECISION-NEEDEDs and re-labels the sites those verdicts bind; no stage kickoff governs it. ## Parked questions - The #5 naming rule's falsifier is **live and unspent** (n=2, readings 6.8% apart): a third reading showing a seat-constant residual would justify collapsing back to one term. - ADR-3's share stays `UNMEASURED — channel absent` until one `/context` reading on a post-S-G seat — cheap, and the natural first task of whichever stage next needs the figure. ### §1.7 Forward-check applied - **Principle-level:** `packages/core/principles/10-research-patch-annotation.test.ts:23` (scope annotation) green on the new patch; `13-phase-research-coverage-s17.test.ts:138` **caught a real gap in this PR's first draft** — a backward-check shipped with no forward-check. Recorded as an incident in the patch (§4), not silently fixed. Full suite: 37 files / 353 tests green. - **Commit-level:** not a capability commit per `CLAUDE.md` (no dependency, no file ≥50 LOC under a new `packages/core/` subdir, none ≥80 LOC under `packages/`) → `Prior-art:` escape hatch with rationale on the commit. - **Doc-authority:** the design spec is absent from the Artifact Ownership Contract and is stage-edited by design — S-L §6 recorded `docs/superpowers/specs/2026-07-31-arch-v2-context-pipeline-design.md:155` as `GAP-FOUND, routed`, i.e. an edit deferred until this verdict existed. - **600-line markdown gate:** `.claude/orchestrator-prompts/arch-v2-context-pipeline/kickoff.md` edited **in-cell only** — 592 lines before and after (`wc -l`). - **Kickoff-staging-placement** (`.claude/rules/kickoff-staging-placement.md`): the kickoff edit targets `staging`, where `/pipeline` and aif read it. ### §1.7 Backward-check applied **Class** = a live surface using «harness remainder» bare as a *quantity* label, or stating a repo-owned always-on *share*. Population: `grep -rn` over `*.md`/`*.sh`/`*.ts` (38 hits) + the share sites. - `docs/superpowers/specs/2026-07-31-arch-v2-context-pipeline-design.md:155` (bare term) and `:151` (stale «29-39%») — **GAP-FOUND → fixed** (now `:161`, `:170`). - `.claude/orchestrator-prompts/arch-v2-context-pipeline/kickoff.md:102,273,309` — **SWEPT-CLEAN, out of class**: artifact titles (the P14 deliverable / merged patch filename). - `scripts/check-alwayson-budget.sh:13`, `packages/core/hooks/pre-push.ts:1252`, `.github/workflows/audit-self.yml:827` — **SWEPT-CLEAN**: already `UNMEASURED — channel absent` (PR #1265); verified the new ADR-3 wording agrees with all three. - Closed stage kickoffs (`.claude/orchestrator-prompts/arch-v2-context-pipeline-s-e/kickoff.md:135`, `arch-v2-context-pipeline-s-h/kickoff.md:6,69`, `arch-v2-context-pipeline-s-l/kickoff.md:88,152`) and the closed `session-start-token-audit` umbrella (`done.md` present) — **out of class**. - Seven research patches carrying the term — **out of class**, append-only; corrections land as a new patch, which is this one.
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
skills/rules-as-tests/references/{overview,ai-traps}.mdon first run.framework-self-research+framework-self-synth(mirror existingframework-self-detect). All 3 self-application layers now have CI invariant.Architectural pivot — deterministic v1 (no LLM): mirrors Phase 4 «deterministic bridge over AIF» playbook. Project tenet «documents lie; tests don't» demands snapshot-testable v1; LLM-driven extension layer = strict superset for v2 trigger (first real consumer or Phase 8 acceptance test). Native Anthropic SDK
web_search_20250305 allowed_domainsdocumented as v2 contract (Phase 5 research §3.3).Phase 5/6/7 reordering note (please read before reviewing §6)
EXECUTION-PLAN §6 was reordered:
Rationale: linear data flow
0→1→2→3→4→5per architecture.md §2.1. L4 Validator gates synthesized output — without L2/L3 there is nothing beyond Phase 2 manifest meta-tests for L4 to validate. L5 Installer needs L3 output to install.The Phase descriptions in EXECUTION-PLAN.md §6 retain their original headings for diff hygiene; a header-level note added to §6 documents the mapping. Read via the mapping, not the headings.
Test plan
make self-audit)framework-self-research: zero drift across 3 canonical sourcesframework-self-synth: own-repo + fixture snapshots stableAcknowledged trade-offs (NOT regressions)
packages/preset-next-15-canonical/— explicitly deferred to Phase 6 v2 / Phase 7. Split-point: requires recipe coverage of all preset-next-15 rules (R12, R14, R20). Trigger to close: Phase 8 acceptance test (Next 15→16) or explicit Phase 7 scope expansion. Self-app score 8/10 reflects this ‑1.Retros
Phase 7 entry triggers
7 open questions surfaced in retros/phase-6.md, key one: 6-gate L4 Validator triage (Schema / rule-tester / mutation / tautology / two-AI / cross-rule conflict) — which ship Path A v1 vs deferred.
🤖 Generated with Claude Code