Skip to content

fix: let capture resolve and intent seed stamp a valid impact#136

Open
REPPL wants to merge 3 commits into
mainfrom
fix/iss-117-impact-write-paths
Open

fix: let capture resolve and intent seed stamp a valid impact#136
REPPL wants to merge 3 commits into
mainfrom
fix/iss-117-impact-write-paths

Conversation

@REPPL

@REPPL REPPL commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Fixes the write paths behind ledger issue iss-117 (major): abcd capture resolve and the intent seed-draft path could not set impact, so records the tool itself produced were rejected by its own issue_impact_valid / intent_impact_valid record-lint blockers.

What changed

  • capture resolve gains --impact, validated in the core via the shared changelog.ParseImpact enum — no default, empty/invalid refused (enforced in core, not MarkFlagRequired, preserving the CLI's zero-required-flags invariant).
  • Intent seeding (CreateFromText/seedDraft) gains an optional impact, rejecting internal (intents are user-facing by definition).
  • internal/core/capture/serialize.go: new rawScalar type writes the impact bare (impact: fix) rather than YAML-quoted (the quoted form fails the blocker); byte-guarded against structure injection.
  • Sibling-site sweep: capture wontfix ruled out (wontfix records carry no impact gate); intent Plan/Reconcile ruled out (frontmatter survives the rename; Reconcile must not auto-invent impact — the gate correctly prompts the human).
  • Docs updated end to end: commands/abcd/capture.md, commands/abcd/intent.md, regenerated CLI reference + surface registry, CHANGELOG entry.
  • Second commit dogfoods the fix: iss-117 is resolved open/ → resolved/ by the fixed verb itself, with impact: fix stamped — the ledger move rides this branch (no trailing chore PR).

Verification

  • New tests watched fail first (the verbs had no way to set impact), then pass: TestResolveProducesImpactValidRecord and TestCreateFromTextStampsImpact lint the produced records with the real blockers and get 0 findings.
  • Gate (run independently by the orchestrator, not taken on trust): make preflight exit 0 (build, gofmt, vet, tests, race) and record-lint exit 0 blockers.
  • Independent correctness + security reviews ran on the full diff before this PR opened; both returned PROMOTE with no blocking findings. The security pass attacked the bare-scalar injection guard directly (enum exact-match upstream, ASCII allowlist in the serializer, re-parse + re-validate on transition) and refuted every vector.

The correctness review confirmed one pre-existing sibling outside this item's scope: the intent ship path (Reconcile, internal/core/intent/lifecycle.go) cannot stamp impact, so a no-impact seed can still reach shipped/ and trip intent_impact_valid. Recorded as iss-126 (third commit on this branch) rather than fixed here — finding first, fix behind an armed detector.

Validators were deliberately not touched — root-cause class is the write paths.

REPPL added 3 commits July 25, 2026 14:19
The issue_impact_valid and intent_impact_valid record-lint blockers require
a valid impact on records in the release set (resolved/ issues, shipped/
intents), but the verbs that mint those records had no way to set one. The
tool's own path therefore produced records its own gates reject: `capture
resolve` moved an issue to resolved/ with no impact, and `intent "<text>"`
seeded a draft that carried no impact through planning to shipped/.

capture.Resolve now takes a required Impact, validated against the shared
changelog enum (no default — empty or invalid is refused, never guessed) and
written bare (impact: fix), never YAML-quoted, so the frontmatter line-scanner
and the enum agree. intent.CreateFromText takes an optional impact, validated
the same way and rejected as internal (an intent is user-facing by
definition), stamped onto the draft so it survives the impact-preserving move
to shipped/.

The --impact flag on `capture resolve` is enforced in the core rather than via
cobra MarkFlagRequired, keeping the CLI tree's no-required-flags invariant
(TestLiveTreeMarksNoFlagRequired). capture wontfix is untouched: a non-action
ships nothing, so wontfix/ carries no impact.

Resolves ledger iss-117.

Assisted-by: Claude:claude-opus-4-8
Dogfood proof of the impact write-path fix: `abcd capture resolve iss-117
... --impact fix` moved the record open/ -> resolved/ and stamped a bare,
valid impact, which record-lint's issue_impact_valid accepts (0 blockers).

Assisted-by: Claude:claude-opus-4-8
The iss-117 correctness review confirmed a pre-existing sibling of the
same class: Reconcile mints shipped/ records gated by intent_impact_valid
but has no way to stamp impact. Recorded first, never fixed ahead of an
armed detector.

Assisted-by: Claude:claude-fable-5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant