feat: new read modalities - #106
Merged
Merged
Conversation
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
A family of body-aware read/write commands across task/epic/audit, plus a lint
guard for acceptance-criteria misconfiguration. Driven by two rounds of agent
dogfooding feedback; the unifying theme is teaching the CLI that a document's
structure — sections, acceptance criteria, progress — is first-class, not an
opaque blob you can only append to.
What's in it
Metadata reads (token-cheap, no body)
task info/audit info(+--json) — path + triage fields + a tally(
ac:{checked,total}for tasks;findings:{total,open,in_progress,done,dropped}for audits)
task path/epic path/audit path— just the absolute file path,parse-free so it still works on a file with broken frontmatter (exactly when
you need the path to go fix it)
Section-scoped reads
task/epic/audit show --section <name>and--frontmatter-only— narrow abody to one section, or drop it, via a shared fence-aware section slicer
Acceptance-criteria writes
task ac— numbered--list;--check <n>/--uncheck <n>flip one criterionby index. Surgical (a check→uncheck round-trip restores the file byte-for-byte),
atomic (through
EditBody), idempotent (a no-op write is skipped), fence-awareLint guard (make misconfiguration loud, not a silent false positive)
lintnow flags malformed acceptance checkboxes ([],[ x], …) and duplicateacceptance sections, so a wrong
ac:tally can't be silently trusted.Deliberately conservative — citations
[1], markers[-], and[text](url)links are not flagged — via a new one-pass
ListTasksWithBodiesscan (noO(N²) re-resolve)
Foundations
internal/domain/body.go— a pure, fence-aware body-structure model (CommonMark-ishfence tracking that honors fence char+length; CRLF-tolerant):
Section, theacceptance enumerator/flip, and the lint guard
render.fieldPrinter,narrowBody/addBodyScopeFlagstask_info/audit_info/path/acceptanceenvelopes;SchemaVersion
1.26 → 1.29Contract & tests
--jsonon every new surface with aschema_version; new envelopes validateagainst the reflected JSON Schema and are pinned in the golden machine-contract
suite (path-bearing goldens redacted so they're portable across machines/CI)
just build·test·lint·docs-check·tidy-checkall greenReview
Went through three rounds of external adversarial review. Fixes made along the way:
CRLF-blind heading parsing, CommonMark nested-fence tracking (a naive toggle leaked
nested content), a TTY path-truncation regression from the shared field renderer, a
golden-portability gap on Windows, and a self-inflicted lint false positive (a
"## Progress … acceptance" heading miscounted as a second acceptance section) — all
regression-tested.
Planning
Self-hosted under
planning/: closesstructure-aware-body-mutation-and-metadata-reads(epic 20). Its one blocked item,task log(append a dated progress entry), is spun off to its own task becauseit needs a canonical-progress-shape decision first — not in this branch.
🤖 Generated with Claude Code