Trinity agent - #1
Open
vichitra-studio wants to merge 6 commits into
Open
Conversation
vichitra-studio
added a commit
that referenced
this pull request
Apr 30, 2026
…[drift-fixes] Drift #1 — prompt_16a field-name drift: - Remove literal `assumption` field reference from prompt_16a_impl_planner.md; adopt schema-pointer style matching other prompts (schema owns field names). - Add `proposed_assumption` to field shape bullet list (source, impact, proposed_assumption). - Migration template documents legacy assumption → proposed_assumption rename. Drift #2 — hallucination-lint E530 wrapping pressure: - Add canon-ref bypass: sibling command_ref with structurally-resolved cn:* id skips prefix check; actual ref resolution stays with canonical-integrity (E110/E210). - Add project-level allowlist merge: _load_command_prefixes now accepts project_canon_dir and merges <spec-root>/canon/command_prefixes.json into toolkit defaults via shared _merge_prefixes_from_file helper. - command_prefixes.json: add _description clarifying scope (universal verbs only). - Add _unwrap_shell_c to _extract_path_from_string so bash -c "..." wrappers do not trigger false LINKED_TEST_FILE_NOT_FOUND on linked_test_expectation. - Rewrite E530 message to name both escape hatches (message preserves INVENTED_ENUM_OR_ID substring for backward test compatibility). DRY / SoC: - Extract extract_command_string() and is_resolved_canonical_ref() into linter_utils.py; import in step_16.py and hallucination_lint.py respectively. - Relocate _is_resolved_ref from canonical/integrity.py to linter_utils.py; re-import under same alias — no API change, no circular import. step_16.py: apply extract_command_string at all three E301/E302 enforcement sites so object-form test_commands[] items (schema oneOf [string, object]) are validated symmetrically with string-form items. schema/16_impl_context.schema.json: add 'task' to spec_ref.type enum and corresponding skip in _check_behavior_validation_pairing (intentional, unrelated). prompts/16b + 16c + migration template updated to document new object-form shape and both escape hatches. CLAUDE.md troubleshooting section updated. Tests: 189 passing; new end-to-end tests (no mock-what-we-test violations) cover both escape hatches, malformed allowlist fallback, bash -c unwrap, and object-form E301/E302 across all three step_16 sites. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
vichitra-studio
added a commit
that referenced
this pull request
Jun 24, 2026
… host CI validate-all Resolves the single P1 (D11) finding from the fresh re-audit of d67fbea, plus a same-class bug it surfaced in the generated host CI workflow: - D11: the source_of_truth/render_target extension to changelog/format.yaml (an enforced schema surface consumed by changelog_parser.py) is now documented with a change_schema entry in changelog/unreleased.yaml and a mirroring bullet in changelog/unreleased.md (source/render parity preserved: 5 entries <-> 5 bullets). - init_project.py _render_ci_workflow: the generated host CI step ran the bare `validate-all spec --repo-root ./devspec_toolkit` (no --spec-root/--git-root), so project canon was not discovered and every host PR emitted false E110s. Now runs `spec-check spec --repo-root ./devspec_toolkit --spec-root ./spec --git-root .`, matching the pre-commit hook fix and CLAUDE.md core rule #1. - Added test_ci_uses_spec_check_not_validate_all asserting the generated CI uses spec-check with both project-canon flags and no validate-all (closes the I8 test gap that let this hide); documented the CI fix in both changelog files. Full suite: 2819 passed, 4 skipped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
vichitra-studio
added a commit
that referenced
this pull request
Jul 12, 2026
…#19) * fix(DEVSPEC-103,105,106): fix generated pre-commit hook config for macOS + submodule deployments - Replace bare `python` with `devspec_env/bin/python` in all hook entries (macOS ships no bare `python` binary; venv-pinned interpreter required) - Rename validate-all hook to spec-check; swap subcommand + add --spec-root ./spec --git-root . flags to seed-lint and canonical-integrity - Fix governance hook: pass_filenames false→true so pre-commit passes the commit-msg file path as a trailing positional arg consumed by --message; --message must remain the last flag - Fix bare-prefix substitution in _build_pre_commit_config: add second replace pass for devspec_toolkit/ (files: patterns) after ./devspec_toolkit (flag patterns) to avoid partial substitution when toolkit root differs - Expand hook-presence tests: add dag-lint, extraction-intent-check, canon-schema-alignment, canonical-integrity presence assertions; strengthen path-substitution test to cover both ./prefix and bare-prefix forms Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(DEVSPEC-104): relax canon schema minItems:1 to allow empty bootstrap registry New host repos bootstrapped by init_project.py start with entries:[] in spec/canon/manifest.json — the prior minItems:1 constraint on vc:core:canon caused E520 schema_invalid on every new project until after Step 03 (specdev canon-accept). Set minItems:0 to reflect that an empty project-canon registry is valid during the bootstrap phase. Adds a regression test verifying that a bootstrap manifest with entries:[] passes lint_canon_dir schema validation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(DEVSPEC-104): address pr-audit findings — changelog, lifecycle tests, schema read - changelog/unreleased.yaml: add fix entry for pre-commit hook changes (devspec_env/bin/python path, validate-all→spec-check rename, flags) - changelog/unreleased.md: populate Fixed section with both fix entries - test_canonical_lint.py: add sunset/retired E420 lifecycle negative tests; replace hardcoded inline canon schema with real schema/core/canon.schema.json read - test_init_project_submodule.py: add fallback-path test for missing template; extend test_path_substitution_applied to assert devspec_toolkit/tools absent Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(audit-20260623): resolve 9 pr-audit findings — fixtures, lint tests, changelog parity, extractor Remediates all findings from audit run 20260623-091938-fbe17bf: - T1-T3 (D5): canon fixture manifests drop forbidden root key canonical_refs_used and add required entry fields; consumer tests (E410 alias collision, E420 deprecated-timestamp) preserved. - T4 (I8): negative test that lint_canon_dir() rejects manifests with additionalProperties via E520 schema_invalid. - T5 (I8): test for the alias-branch E420 deprecated-lifecycle path (lint.py:194-198), distinct from the entry-level branch. - T6 (D11): document devspec-governance commit-msg hook pass_filenames false->true fix in changelog Fixed section. - T7 (I11): extractor YAML branch now populates typed Keep-a-Changelog arrays via an explicit change_type->category map (no prefix rule, so rename_*/merge_steps/split_step/internal_restructure are not dropped); regex fallback emits dicts; EXTRACTOR_VERSION 1.0.6->1.0.7. - T8 (D11): declare source_of_truth/render_target on unreleased.yaml and register both keys in format.yaml optional_fields. The pass_filenames fix is also added to unreleased.yaml so the source actually contains what the .md render shows (parity holds, not just keys present). - T9 (D12): reclassify the minItems-relaxation entry fix->change_schema. Full suite: 2818 passed, 4 skipped. All per-task acceptance gates green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(audit-20260623-2): document format.yaml extension + fix generated host CI validate-all Resolves the single P1 (D11) finding from the fresh re-audit of d67fbea, plus a same-class bug it surfaced in the generated host CI workflow: - D11: the source_of_truth/render_target extension to changelog/format.yaml (an enforced schema surface consumed by changelog_parser.py) is now documented with a change_schema entry in changelog/unreleased.yaml and a mirroring bullet in changelog/unreleased.md (source/render parity preserved: 5 entries <-> 5 bullets). - init_project.py _render_ci_workflow: the generated host CI step ran the bare `validate-all spec --repo-root ./devspec_toolkit` (no --spec-root/--git-root), so project canon was not discovered and every host PR emitted false E110s. Now runs `spec-check spec --repo-root ./devspec_toolkit --spec-root ./spec --git-root .`, matching the pre-commit hook fix and CLAUDE.md core rule #1. - Added test_ci_uses_spec_check_not_validate_all asserting the generated CI uses spec-check with both project-canon flags and no validate-all (closes the I8 test gap that let this hide); documented the CI fix in both changelog files. Full suite: 2819 passed, 4 skipped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(submodule): pass project-canon flags on spec-validating command examples Submodule-deployment doc examples and two prompt-contract seeds invoked spec-validating commands without --spec-root/--git-root, so a host following them would not resolve project canon and would see false E110s — the same bug class fixed in the generated CI workflow (init_project.py). Flag-consistency pass across reference.md and the three workflow runbooks: every command confirmed to accept both flags (validate-all, matrix, fixtures-lint, seed-lint, traceability-check, hallucination-lint, spec-quality-lint, canonical-integrity, invariants-check, governance-check) now passes --spec-root ./spec --git-root . in submodule examples. Commands that take only --repo-root (dag-lint, canonical-lint canon, diagnostics) and single-file `validate spec/NN.json` forms are deliberately left unchanged. The reference.md "Standard (non-submodule) usage" example is intentionally kept flagless to contrast with the submodule example beside it. Contract seeds switched to the unified gate to match init_project.py: - prompt_12_ci_gates.md: example CI gate -> spec-check + project-canon flags - prompt_15_scaffold.md: example scaffold validator -> spec-check prompt-sync: OK. Full suite: 2819 passed, 4 skipped. Changelog parity preserved (6 yaml entries <-> 6 md bullets). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(audit-e953793): correct doc flags, prompt examples, changelog accuracy, venv-name propagation Remediates the 10-task fix plan from PR audit run 20260623-191127-e953793 (theme-based fresh full re-audit of bugs/1.1.1). Applied in 4 file-disjoint chunks, each verified by a fresh full reviewer against schema/canon authority. Host code: - T1 init_project.py: thread --venv-name through _build_pre_commit_config (mirrors _render_ci_workflow); parametrize governance hook; add discriminating custom-venv test. Default output byte-identical. - T10 extract_digest_changelog.sh: PYTHON=${DEVSPEC_PYTHON:-python3} + Py>=3.9 note. Docs (flag-consistency per CLAUDE.md submodule matrix): - T4 reference.md: add spec-check; fix forward-replay-check & canonical-lint flags. - T5 workflow_bootstrap_legacy.md: canon-accept --git-root; canonical-lint flags; spec-check. - T6/T7 workflow_{feature_extension,migration}.md: spec-check alongside validate-all. Prompts: - T2 prompt_15_scaffold.md: replace invalid 'specdev-tools' prefix with run_specdev.sh + flags. - T3 prompt_12_ci_gates.md: populate canonical_refs_used with cn:core:environment:ci. Changelog: - T8 unreleased.yaml: correct false parser-consumption claim (keys are permitted optional fields, neither required nor read). - T9 unreleased.md: re-render change_schema entries under ### Changed; 6:6 YAML/MD parity. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(audit-5486e9a): resolve 4 mechanical findings from terminal re-audit Follow-up to 5486e9a. The terminal theme-based /devspec_pr_audit (run 20260624-115549-5486e9a) confirmed the prior 10-task fix plan resolved + clean, and surfaced 5 new findings. This commit lands the 4 mechanical ones (each fresh-reviewed, full test suite green); the 5th (governance commit-msg hook pass_filenames) is a CLI-contract design decision deferred separately. - reference.md: add --spec-root/--git-root to canon-schema-alignment example (cli.py:400-405 accepts + consumes them; matches ~10 sibling examples the branch already updated). - prompt_12_ci_gates.md: Operating-Flow Gate bullet now lists spec-check not validate-all (consistent with the corrected example + Core rule 1). - changelog/unreleased.{yaml,md}: reword changes[3] — drop ambiguous "neither required nor read"; state precisely that source_of_truth/ render_target are declared optional_fields accepted as top-level keys without their values being consumed. 1:1 YAML/MD parity preserved. - test_init_project_submodule.py: scope the os.path.exists mock to init_project.os.path.exists. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(seed-lint): add W555 for thin Step-00 out_of_scope seeds (DEVSPEC-107) Seed-lint passed silently when seeds routed to Step 00 carried no out-of-scope / non-goal content, yet the charter schema mandates out_of_scope minItems:3. Authors hit a gate-fail-or-hallucinate fork at Step 00, one phase after the seed layer where the gap originates. Add W555 STEP00_SEED_OUT_OF_SCOPE_THIN: warn-only and non-promotable. It aggregates substantive out-of-scope items across ALL Step-00-routed seeds and fires once if the combined count < 3, mirroring the charter schema constraint at the seed phase. Non-promotable by design: an error would recreate the same fork upstream for legitimately sparse projects. The counter skips bracket-placeholders, template scaffold labels (**Expectation**:/**Content**:), empty bullets, and backtick/tilde fenced code blocks. Detection is gated on "00" in step_requirements. Also update seed_overview.md §3.2 to mirror §3.1's "list at least 3" guidance so the template stops nudging authors into the shortfall. Verified end-to-end: W555 surfaces in default `specdev spec-check` output for a thin seed and is absent for a rich one. Full suite green (2839 passed). Unit + integration coverage added; no mocks of code under test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(audit-fc11407): resolve 3 P2 findings from W555 commit-scoped audit Commit-scoped PR audit of the W555 changeset (run 20260624-195742-fc11407, --base f4336cb) returned STATUS OK with 4 P2 findings. Dispositions: - T1 (D10, fix): _count_substantive_out_of_scope tracked fenced code blocks with a single boolean toggled by both ``` and ~~~, causing cross-delimiter leakage (a ```-opened fence containing a ~~~ line flipped the state, so in-fence bullets were counted / out-of-fence bullets skipped). Now tracks the opening delimiter and closes only on a matching delimiter. Added discriminating test test_fires_when_cross_delimiter_fence_contains_fake_bullets. Fence-length matching per CommonMark remains the documented accepted limitation. - T2 (D14, won't-fix): the minItems:3 threshold stays restated inline rather than read from 00_charter.schema.json at runtime. Documented the rationale in code: it follows the validation layer's mirror-with-comment convention (step_16, step_16b, linter_utils) and avoids coupling the seed layer to a Step-00 schema — the separation W555 exists to preserve. - T3 (I8, fix): test_non_promotable_codes_excluded omitted W553/W554/W606 from its non_promotable assertion set (pre-existing debt; errors.py already lists them). Folded them in since this commit touches that exact assertion. - T4 (I12, fix): corrected an inverted comment in the integration test — E520 missing_schema_uri IS emitted when $schema is absent; it is simply irrelevant to the W555 assertions. Full suite: 2840 passed, 4 skipped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(audit-6bf1660): make cross-delimiter fence test discriminating + doc fenced-block exclusion Re-audit of the W555 remediation (run 20260624-215210-6bf1660, --base f4336cb, AHEAD=2) returned STATUS OK with 2 findings. Both fixed: - I8 (P1, test): test_fires_when_cross_delimiter_fence_contains_fake_bullets had no discriminating power — its fake bullets sat under "## 2. Examples" (not an out-of-scope heading), so in_section was never True for them and they could not be counted under ANY fence implementation; the assertion passed for both the correct fence_char impl and the old boolean-toggle bug. Rewrote the seed so the fake bullets live inside a backtick-opened fence containing a ~~~ line AND under the out-of-scope heading, with one genuine bullet outside. Now the correct impl keeps the fence open (count=1 → W555 fires) while the old impl toggles the fence off at ~~~ and counts the fake bullets (count=3 → no fire). Added a direct _count_substantive_out_of_scope == 1 assertion alongside the W555-fires assertion. Discrimination verified: real function returns 1, a throwaway old-impl simulation returns 3. - D3 (P2, doc): error-codes.md W555 "Substantive" definition listed only two exclusions (bracket placeholders, scaffold labels); added the third the code enforces — content inside fenced code blocks (``` or ~~~). No production code changed (seed_lint.py untouched). Full suite: 2840 passed, 4 skipped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(audit-8e68b93): document+test pre-existing E410, fix doc/test-count staleness Round-3 audit (run 20260624-231358-8e68b93, --base f4336cb, AHEAD=3) returned STATUS OK with 5 findings. All resolved (user opted to also clear the pre-existing E410 debt surfaced because seed_lint.py is in the diff): - D3 (P1): E410 CANONICAL_ALIAS_COLLISION was emitted (canon lint + seed-lint duplicate seed_id) but undocumented. Added an error-codes.md entry covering both trigger contexts with resolutions. Pre-existing behavior — no code change. - I8 (P1): the seed-manifest duplicate-seed_id -> E410 path had no test. Added test_duplicate_seed_id_fires_e410 (real temp-dir manifest with two entries sharing a seed_id; asserts E410; no mocks). - D7 (P2): W555 doc now notes fence tracking matches the opening delimiter (a ~~~ inside a ```-opened fence is content, not a close). - D3 (P2): integration test docstring "17 unit tests" -> "18". - I12 (P2): unit-test module Coverage list now enumerates the 18th (cross-delimiter fence discrimination) test. No production code changed (seed_lint.py untouched). Full suite: 2841 passed, 4 skipped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(DEVSPEC-100): Phase 1 remediation checkpoint — WI-1..WI-8 Eight converged work items (P1 crashes + silent-under-review), each driven through a fresh-reviewer review-fix loop to zero findings. Checkpoint commit so per-unit diffs stay clean for Phase 2 review. - WI-1: p5_finalize.py 3-site absent-fix_plan crash fix + G3 blocked-status guard + new test_p5_finalize.py (4 ACs) - WI-2: specdev-trinity reviewer dispatch milestone_start_ref injection + step-5b actions[].target primary read - WI-3: pr-audit-context-author routing.json p0/ path fix - WI-4: pr-audit-discovery-mechanical registry-generate --dry-run -> --out (3 sites) + D1 failure-mode row - WI-5: specdev-step existence check + specdev-impl author-mode questions[]-shaped blocker (F-4 two-surface contract) - WI-6: skill frontmatter disambiguation + delete specdev-trinity-plan skill + init_project allowlist + trinity body-note removal - WI-7: specdev-review wave-loop model (deterministic theme clustering) + theme_group enum + SPECDEV_REVIEW_CONCURRENCY - WI-8: specdev-trinity post-convergence 16c evidence-synthesis (F-1 two-branch fr_coverage) + new test_wi8_green_derivation.py (anchored) Plan + per-unit review records: WIP/devspec-100/ (untracked). Follow-ups parked: FU-1 (D9 extraction_paths gap), FU-2 (CHANGELOG note). Not pushed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(DEVSPEC-100): Phase 2 Wave B1 — WI-10, WI-9, WI-13, WI-14 IU-9 (WI-10): trinity SKILL.md — add 'orchestrates, does NOT author' to folded description scalar (exactly once; closes WI-6 AC8), Prerequisites section, error message -> /specdev-step 16a. IU-10 (WI-9): specdev-review SKILL.md Step 2a — per-round full+fresh invariant. IU-13 (WI-13): pr-audit-context-verifier — kind enum defers to schema authority (11 values incl seed-grounding), mirrors sibling agents. IU-14 (WI-14): pr-audit-discovery-semantic — remove forward_to_p3 phantom flag. All four converged ZERO-FINDINGS on round 1 of fresh full review. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(DEVSPEC-100): Phase 2 IU-11 (WI-11) — pr-audit bin-packing budget + theme grouping protocol.md §3: raise per-bin budget ~200 -> ~600, add ~800 hard cap with precedence (cap > budget > ceil(N/3)), theme-first packing, two worked examples, orphan cross-theme co-location capped at ~800. pr-audit-context-author.md step 6: replace global impact-sort with slice(=theme)-first grouping from routing.json; waves <=6 bins; own concurrency env var (not SPECDEV_REVIEW_CONCURRENCY). Theme grounded in existing slices.yaml/routing.json taxonomy (no invented semantics). Converged round 2 (1 LOW consistency defect fixed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(DEVSPEC-100): Phase 2 IU-12 (WI-12) — post-fix verification + fix-apply automation Deliverable A (verification): NEW scripts/p6_verify.py — reads fix_plan.json, runs each task's acceptance_command in topological order (DFS, cycle + unknown-dep detection), reports pass/fail per task (exit 0/1/2). protocol.md §12 documents the workflow. p5_finalize.py build_summary() now EMITS the conditional '## Next steps' SUMMARY.md footer when findings>0 (was doc-only; closes AC2). SKILL.md §9 footer format + --post-fix subsection. Deliverable B (auto-apply): NEW agent pr-audit-fix-apply.md (Option B-NL) — per-task apply-then-gate-on-acceptance_command with max_rounds retry; reuses specdev-trinity-impl pattern; no schema change. Tests: test_p5_finalize.py +2 discriminating footer tests (present/absent) → 6 passed. Converged round 2. Known documented trade-off (AC4): --post-fix re-audit runs full branch diff (touched files are a subset); no --only-files scoping primitive — see FU-3. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(DEVSPEC-100): Phase 2 IU-15 (WI-16) — wire validate_agent_outputs blocked-status gate validate_agent_outputs.py: on strict-mode schema-failure, merge-write {status: blocked, blocked_reason: '<schema> failed validation for <artifact>'} into <run-dir>/manifest.json before exit 1 (new _write_blocked_manifest helper; preserves other keys; safe when manifest absent). Manifest path derived from --run-dir (no --manifest flag). SKILL.md: new explicit P4->P5 gate section — run validate_agent_outputs.py --run-dir <dir> --strict; non-zero -> P5 skipped; documents blocked_reason. Closes the loop WI-1's G3 guard left open (guard already prints blocked_reason). Smoke-tested end-to-end (writer + p5_finalize reader agree on path). Converged R1. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(DEVSPEC-100): Phase 2 IU-16 (WI-15) — broaden pr_audit integration test harness test_p5_finalize.py: +2 (malformed findings -> exit 2; missing manifest -> exit 1). test_validate_agent_outputs.py (NEW, 2): absent fix_plan -> exit 0 not-blocked (regression lock); schema-invalid -> manifest status=blocked + blocked_reason, exit 1 (exercises IU-15's _write_blocked_manifest write-path, per R3-1 ordering). test_tier0_checks.py (NEW, 8): zero-findings-per-check paths; T0-10 specdev-unavailable -> P2 gap kind/catalog_tag=D9 finding. All fixture-based file-in/file-out via main()/direct calls. 18 passed. Tests verified faithful to real script behavior (no fabricated-behavior tests). Converged round 2 (2 LOW unused-import removals). Test-only; no script changes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(DEVSPEC-100): Phase 3 Wave C1 (IU-17/18/19) — trinity errors_remaining, p2/-absent meta-finding, T0-09 CLI prefix IU-17 (WI-17): specdev-trinity-impl.md execute mode — non-zero run_command exit now maps to gate_status:"errors" + errors_remaining (exit code + truncated stderr), NOT ambiguities_raised[]; errors_remaining added to both execute-mode return-contract examples (clean + partial) for shape consistency. IU-18 (WI-18): pr-audit-cross-boundary.md Mode B — emit a p2/-absent meta-finding when the p2/ fragment dir is missing instead of silently skipping; procedure prose, failure-modes table, and invocation template all aligned. IU-19 (WI-19): tier0_checks.py T0-09 — broaden the CLI-change trigger from a single cli.py equality to CLI_PATHS set + CLI_PREFIX (commands/) prefix match, closing the commands/ subpackage coverage hole; +2 discriminating tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(DEVSPEC-100): Phase 3 IU-20 (WI-20) — author-extend mode for additive artifact edits Adds a third specdev-impl mode, author-extend, for additively inserting new operator-intent content into an EXISTING spec/NN artifact (vs author, which re-authors the whole file). Approved design: WIP/devspec-100/wi-20-design.md. - .claude/agents/specdev-impl.md: new "Mode: author-extend" section — detect existing artifact (Bash ls), read via `specdev json read`, subagent authors the content object from intent (+optional seed_path) + prompt contract + upstream, apply via `specdev json insert/patch` (NEVER Write). Post-insert gate = the same SCOPED spec-check reused from author/fix (no full forward-replay by the leaf agent) + always emit a forward_replay_debt notice referencing the existing W595 CONTENT_STALENESS code. Own blocker counter author_extend_blocker_round. - .claude/skills/specdev-step/SKILL.md: `--extend "<intent>" [--seed <path>]` arg + Step-1 dispatch path sending ONLY {mode,target,intent,seed_path?} (thin orchestrator — no content payload built); author_extend_blocker_round bridge. Dual fresh review (cross-file dispatch seam + design/AC fidelity): no P1/P2; 2 LOW — allow-list seed_path precision (fixed), insert_pointer consumer-side row (accepted as designed per §4 defense-in-depth). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(DEVSPEC-100): F-1b — reviewer FR-coverage gate matched zero FRs (false-negative) specdev-trinity-reviewer.md criterion #6 ("Linked-fixture coverage rolled up") selected FR bindings via spec_ref.type=='doc' / id=='vc:04-fr-list', but real ms_*_plan.json fixtures encode FR bindings as spec_ref.type=='fr' (id e.g. fr-user-login). The old selector matched zero checklist items, so the fixture-coverage gate silently never fired — a milestone shipping with missing fixture coverage would never raise kind:coverage. Same root cause as WI-8 (which fixed the impl-side FR filter); this fixes the reviewer-side predicate. Doc-criterion change (agent .md), verified statically + against fixtures; no runtime test. Fresh review: CONVERGED. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(DEVSPEC-100): FU-2 — changelog note for removed /specdev-trinity-plan skill WI-6 removed the /specdev-trinity-plan skill (functionality now /specdev-trinity --phase plan). Add the operator-facing migration note to changelog/unreleased.md (### Removed) + unreleased.yaml (internal_restructure) so hosts vendoring the toolkit as a submodule know to re-run init to refresh the stale skill symlink after bumping. Closes FU-2. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(pr-audit): scope --post-fix closing loop via existing --base, not full re-audit The --post-fix closing-loop re-audit re-ran a full P0–P5 audit over the whole branch. p6_verify.py already confirms each fix via its acceptance_command, so the re-audit's only remaining job is to catch fix-introduced side effects — which a diff scoped to the fix changes fully covers. Reuse the EXISTING --base flag instead of building an --only-files primitive: 1. capture PRE_FIX_SHA before applying, 2. apply + p6_verify gate (unchanged), 3. on pass, commit the verified fixes (stage only fix_plan.tasks[].file), 4. re-run /devspec_pr_audit --base <PRE_FIX_SHA> → scopes to the fix commit. SKILL.md §9 + protocol.md §12.2 rewritten; removes the "no --only-files primitive exists" note (no new flag needed). Behavior change: --post-fix now commits the verified fixes (previously left in the working tree) — required for the scoped diff. No-op fixes (nothing staged) skip the commit + re-audit. Full branch-vs-main audit still available via a normal run. Closes the DEVSPEC-121 need without a new primitive; §12.1/§12.3 unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(pr-audit): apply 20260701-125732-47caab1 fix_plan (10 tasks) Remediates findings from the agent-change PR audit (--base 3423097) covering the DEVSPEC-100 agent-contract rewrite and the pr-audit --post-fix refactor: - Real regressions from our own work: unused mode:apply dispatch field (pr-audit-fix-apply.md), a gitignored test fixture that only ran on the author's machine (test_p5_finalize.py AC2), and a failure-signal regex missing non-zero-exit detection (test_wi8_green_derivation.py). - Pre-existing doc drift in touched files: stale digest-directory naming, a wrong schema line citation, a hallucinated "verified" schema claim, and two protocol.md/agent-contract shape mismatches (meta_findings[] fields, fix_plan finding-reference fields). - Changelog backfill for the prompt_16c behavior change, the devspec_pr_audit skill expansion, and the agent-contract rewrites. Deferred (filed as follow-up, not applied here): a new changelog- enforcement CI check and a yaml/md parity test — both new safeguards rather than fixes for anything currently broken. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(pr-audit): apply 20260701-144050-f13cd74 closing-audit fix_plan (4 tasks) Round-2 remediation from the scoped closing re-audit (--base 47caab1) of the first fix batch. The closing audit caught issues the first review-fix loop introduced or left incomplete: - specdev-trinity-reviewer.md: the prior scope_kind fix only corrected one of two identical false claims, leaving a contradiction within the same file (lines 94-95 vs 143-144). - changelog/unreleased.{yaml,md}: two backfilled entries contained factual inaccuracies — validate_agent_outputs.py was not actually broadened for post-fix output shapes (p6_verify.py is the real new artifact), and anchor/roadmap sync is performed by specdev-trinity/SKILL.md's Step C3, not the named agent-contract files. - test_wi8_green_derivation.py: added dedicated assertions for the 'exit code:'/'exit code=' variants the failure-signal regex already handles but the regression test didn't independently verify. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(pr-audit): correct changelog agent-file attribution (round 3) The scoped closing re-audit (--base f13cd74) caught a third defect in the same changelog entry: the internal_restructure note attributed all 11 rewritten .claude/agents/*.md files to "IU-11/12/15/16", but git history shows 4 of them were touched only in Phase 1 (d0724c5) or Phase 2 Wave B1 (2c2f7b6), and IU-15/16 touched zero agent-contract files. Two prior rounds already rewrote this same passage and both introduced new inaccuracies, so per the review-fix loop's stopping rule this fix was made directly rather than delegated a third time, then independently re-verified by a fresh P3 cross-boundary pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(DEVSPEC-122): stop treating deferred/wont-have/out-of-scope as absence across the validation pipeline Root cause (found via a real vc_payments incident: a task had to be deleted rather than deferred because deferring it threw a hard error): many coverage/completeness checks excluded checklist_status:"deferred" (or FR priority:"wont-have", or capability scope:"out") as if the item didn't exist, instead of treating it as "exists, paused/cancelled, documented why." Schema: - 14_roadmap.schema.json: add "deferred"/"wont_do" task status + required status_reason, so a roadmap task can express pause/cancellation directly instead of it being inferred from checklist coverage. - 16_impl_context.schema.json: add "wont_do" checklist_status + required wont_do_reason (enforced via allOf/if/then, not the unenforced prose pattern wont-have/scope:out use). - 08_fixtures.schema.json: out_of_scope[] block (fr_id/rationale), mirroring 05_interface_contracts.schema.json's existing one. 8 confirmed bugs fixed, each empirically verified against real validator output (not just static reading): - E304 ROADMAP_TASK_UNCOVERED: deferred/wont_do checklist items now count as coverage; the milestone-fallback branch skips deferred milestones; a task itself marked deferred/wont_do no longer needs checklist coverage. - E307 BEHAVIOR_VALIDATION_PAIRING: deferred/wont_do items count in the pairing set instead of being skipped. - W576 TASK_EXECUTION_MISSING: skips deferred/wont_do tasks, plus a defense-in-depth check when every covering checklist item is deferred/wont_do but the task's own status hasn't caught up yet. - W568 UNCOVERED_CAPABILITY: exempts scope:"out" and scope:"future" capabilities (the capability-level analog of FR wont-have/deferred). - matrix.py fr_coverage (SPECDEV_MATRIX_STRICT=1): excludes wont-have and Step-05/Step-08 out-of-scope FRs from every fr_with_* ratio, with fr_with_fixture using its own Step-08-based denominator since Step 05 and Step 08 out-of-scope are independent exemptions. - step_11.py W583/W615: red-team threat coverage now traces each API/invariant back to its FR(s) and exempts it only when every traced FR is wont-have. - cli.py completeness-check: total_frs/total_caps denominators now match the exemption sets the checks they summarize actually use (Step-05 vs Step-08 FR exemptions are independent; scope:out/future capabilities both exempt). - New W616 PAUSED_OR_CANCELLED_ITEM_MARKED_VERIFIED: flags a checklist item left at implementation.status:"verified" after being paused or cancelled, found by adversarial testing rather than static reading. Verified via three escalating review rounds: static code read, empirical validator execution against constructed fixtures, and two independent fresh-agent review passes with no memory of prior conclusions. Every new assertion was checked with a revert-source/confirm-fail/restore discriminator to prove it exercises real behavior rather than passing vacuously. No mocking in any new test. Full suite: 2937 passed, 4 skipped, 107 subtests (baseline 2885). specdev registry-generate: zero diff. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(pr-audit): apply 20260702-100406-04dda8d fix_plan (25 tasks) Remediates findings from the DEVSPEC-122 rollout PR audit (--base 3bde863), spanning doc drift, missing error-code documentation, stale comments, and two real gaps in cross-step/traceability validation: - New validation logic: E536 CONTRADICTORY_OUT_OF_SCOPE_FR_FIXTURE (traceability_closure.py) and a Step 08 out_of_scope[].fr_id cross-step check (step_08.py), both mirroring existing E535/E590 patterns; each with a covering unit test. - Bonus fix found while writing T14's regression test (not in the original 25 findings): validate_step_16 dereferenced a non-dict `plan` value without a type guard, crashing before step_16a's own isinstance check could fire its intended E520. Added the missing guard in step_16.py. - Doc/prompt drift: 18 new or promoted error-code headings in error-codes.md, corrected false claims and duplicate bullets in prompt_16a/16b, restored a dropped breaking-change sentence in the changelog, and cross-references/exemption docs across several prompt files. - Fixture completeness: positive + negative fixtures for Step 08's out_of_scope[] field. Three fix_plan tasks (T10, T11, T12) were mis-scoped to a single file by the audit's own P4 consolidation loop even though their change_summary required a source + test file pair; found and corrected during --post-fix dispatch, then implemented directly rather than delegated further given the fabrication risk on the only real logic in this fix_plan. T10's acceptance_command also targeted a pytest file with no collectible tests (always exit 5 regardless of fixture content) — replaced with a direct `specdev validate` gate, verified under the exact subprocess.run(shell=True) mechanism p6_verify.py uses after a first correction attempt still broke on nested-shell $?-expansion. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(pr-audit): apply 20260702-152521-64cd062 fix_plan (19 tasks) Closes 22 findings from the scoped closing re-audit of fix commit 64cd062 (base 04dda8d): backfills ~40 undocumented error/warning codes and a step_16.py E520 message family in error-codes.md, fixes schema/08's allOf/unevaluatedProperties composition (phantom "Unevaluated properties" error), wires the step_08 out_of_scope fixtures into the bridge test suite, adds W570 branch coverage and a step_08 no-phantom regression test, resolves several prompt/docs drift items (prompt_08 downstream count and traceRef pointer, prompt_11 threatCategory restatement, prompt_14 completeness-assessment qualifier, prompt_16a checklist_status delegation and probe-command claim), documents 17 previously-undocumented specdev subcommands in reference.md, and adds changelog entries for the isinstance(plan, dict) guard, E536, and E590. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(pr-audit): apply 20260702-180836-78f7e58 fix_plan (19 tasks) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(pr-audit): apply 20260702-235732-0789b8a fix_plan (4 tasks) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * refactor(pr-audit): switch Tier-2 dispatch from impact-score bin-packing to theme-based The old algorithm computed a per-file impact score (type_weight x expansion-set size x |applies|) and greedily packed files into ~600/800-unit bins, only merging themes with a single changed file. Any theme with >=2 files always got its own bin, which was the dominant cause of over-fragmentation on typical multi-area PRs (up to 15 bins on an 8-theme change). Replace with one discovery-semantic bin per touched theme (slice) by default, each carrying its full applies (drift_types + invariants) set so review of a theme is never split by aspect. Cross-theme merging is removed. A theme only splits into sub-bins on overflow (~15+ files), grouped by pipeline step or shared directory, never by score. Removes now-dead type_weight/complexity_per_file fields from slices.yaml (confirmed unused by any script). Updated protocol.md §3, pr-audit-context-author.md, pr-audit-context-verifier.md, pr-audit-discovery-semantic.md, and SKILL.md consistently. Validated against 7 historical audit runs: bin count drops from 55 to 35 across the sample (-36%), with the two most fragmented runs roughly halved (04dda8d 15->8, 64cd062 14->7). * fix(pr-audit): apply 20260710-183622-68cd048 fix_plan (4 tasks) - SKILL.md: correct tier2_bins shape description ({bin_id,theme,files[]} object, not a bare array) and worked-example sourcing annotation - pr-audit-context-verifier.md: mark the duplicated Output schema constraints block as keep-in-sync with discovery-semantic.md; add a bundle_warnings[] resolution check to the verifier procedure - pr-audit-context-author.md: stop citing nonexistent catalogs.md per-item severity annotations for severity_priors; reframe as agent judgment guided by the general P0/P1/P2 meaning section All 4 acceptance commands verified via p6_verify.py (4/4 PASS). * fix(pr-audit): apply 20260710-191504-117eb16 fix_plan (2 tasks) - pr-audit-context-verifier.md: replace step 10's worked example, which overlapped step 8's existing digests_needed check, with a genuinely distinct case (a missing digest for a file outside any tier2_bins entry); also correct the JSON path shorthand to include the missing .files[] hop - pr-audit-context-verifier.md: fix the keep-in-sync comment above "Output schema constraints" to stop claiming byte-identity with discovery-semantic.md's block (they differ by the upstream_refs[] paragraph, which this file covers elsewhere) and instead scope the sync requirement to the shared core schema-constraint content Both findings were introduced by the prior fix commit (117eb16) and surfaced by that commit's own closing re-audit. Both acceptance commands verified via p6_verify.py (2/2 PASS). * fix(analysis): scan plan.ambiguities[] in upstream-backlog, guard against misfiled anchors DEVSPEC-123: `specdev upstream-backlog` previously only read execution.emergent_ambiguities[] (16b/16c), silently missing plan.ambiguities[] (16a). Now scans both, unified via a shared severity rank across the two vocabularies (blocking/non_blocking vs. low/medium/high/critical), and discloses via new W617 how many records the default --status open view is hiding. Follow-up: a Trinity Anchor misfiled inside impl_context/ (the existing W609 condition) also has a plan.ambiguities[] array, but in the anchor's own crossCycleAmbiguityItem shape, not the 16a binary scale — without a guard it would spuriously fail every entry as E520. _iter_plans now skips artifact_role == "anchor" files, matching validate.py's existing (whitespace-tolerant) discriminator. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(pr-audit): apply 20260711-080019-b7fdff3 fix_plan (4 tasks) * fix(registry): recurse deep-nested registry entries + close seed drift blind spot DEVSPEC-125: two independent toolkit-side gaps. Gap 1 — entry_key_registry omitted the 14_roadmap `criterion` entry (3-deep: milestones -> tasks -> acceptance_criteria). Root cause was a one-level nesting cap: the generator and every consumer used partition("[].") (first-split only). Step 04 (fr -> criterion) is only 2-deep so it masked the gap. Fix: - generate._scan_nested_arrays now recurses, symmetric with the already-recursive registry schema. - new shared iter_array_path(data, path) walker in core/entry_key_registry; list_entries recurses via _flatten_entry. json_utils, matrix, and registry_check adopt the walker (three single-level idioms removed). - registry_check no longer treats a MISSING nested array as drift (nested arrays may be optional, e.g. task.acceptance_criteria; requiredness is owned by schema validation + the regenerate byte gate). It still fires for a present-but-wrong-shape nested array. Top-level behavior unchanged. - regenerated tools/entry_key_registry.json + golden (byte-identical, +1 criterion entry). extraction_paths.json unchanged (top-level only). Gap 2 — seed drift-detection ignored manifest seeds missing from the index. build_seed_index hashes every manifest seed, so an index missing one is stale-by-omission: edits to it tripped no drift signal. check_freshness now cross-checks manifest vs index and marks manifest-only seeds untracked; CLI `context freshness` emits W595 SEED_UNTRACKED. New sub-reason documented in docs/developers/error-codes.md. Tests updated depth-agnostically: the fixture double now carries the 3-deep criterion; four invariant/agreement sites that walked `nested` one level (green only by coincidence — criterion also lives at depth-1 under 04_fr) are now recursive. golden==tools byte-identical; registry-generate idempotent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(pr-audit): apply 20260711-131728-55f376c fix_plan (2 tasks) - error-codes.md: correct the R003/E622 trigger text — it claimed missing arrays are "checked for both top-level and nested arrays", but the prior commit (55f376c) narrowed nested-array drift detection so a missing nested array (which may be schema-optional) is no longer flagged; only a present-but-wrong-shape nested array still fires E622 - registry_check.py: correct the matching module-docstring bullet ("the same two checks apply" for nested arrays), same reason Both were introduced by 55f376c and surfaced by this commit's own closing audit (run 20260711-131728-55f376c). Both acceptance commands verified via p6_verify.py (2/2 PASS). Also fixes a stale fixture path in test_entry_key_registry.py's module docstring (missing tools/ path segment), surfaced by the same audit run as an out-of-scope I12 observation and folded in here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(pr-audit): apply 20260711-140153-017ff65 fix_plan (1 task) error-codes.md: restore the dropped grammatical subject in the E622 REGISTRY_DRIFT trigger sentence at line 995 — the prior fix commit (017ff65) removed "the declared array path is missing," but left the remaining list items ("is not an array, or its entries lack...") without a subject. Introduced by 017ff65 and surfaced by its own closing audit (run 20260711-140153-017ff65). Acceptance command verified via p6_verify.py (1/1 PASS). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(pr-audit): apply 20260711-144049-01e1c62 fix_plan (17 tasks) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(pr-audit): apply 20260711-162609-e06fd20 fix_plan (8 tasks) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(pr-audit): apply 20260711-174402-ec6fc20 fix_plan (5 tasks) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(pr-audit): apply 20260711-183343-6a27cbb fix_plan (3 tasks) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(pr-audit): harden changelog_parser.py against OSError from unreadable I/O Applies 20260711-192839-2396f85 fix_plan (T1: widen validate_changelog's except clause to catch OSError from load_format; T2: test coverage), plus a consolidated pass on the 3 other unguarded exists()/iterdir()/stat() call sites flagged by that run's P3 cross-boundary sweep (list_versions, load_version, get_toolkit_version) — each now degrades to its already- documented failure mode (raise FileNotFoundError, or return None/[]) instead of letting a bare PermissionError/OSError propagate uncaught. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(pr-audit): guard load_format/load_version open() against OSError Closing-audit-5 follow-up on f932289: the OSError hardening pass guarded each function's exists() probe but left the immediately-following open() call unguarded — reachable via cli.py/schema_differ.py callers of load_version() that only catch (FileNotFoundError, ValueError). Wraps both open() calls in try/except OSError, converting to the same already-documented FileNotFoundError contract. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.