docs: complete the Action rename and anchor release dates to git tags - #182
docs: complete the Action rename and anchor release dates to git tags#182flyingrobots wants to merge 4 commits into
Conversation
Follows the Kitten architecture where 'Action' replaces 'Intent' as the Edict-compiled graph rewrite rule, avoiding collision with teleological Kitten 'Intent'.
The workspace-wide Intent -> Action rename in 9f1a11e missed docs/topics/target-ir/README.md entirely and left stale prose in docs/topics/target-ir/test-plan.md, where sentences still said "intent" next to already-renamed evidence names such as action_constraints_and_budget_are_preserved_in_echo_span_ir. The contract-check gate could not catch this: link, evidence-name, and fixture-path checks all still resolved, which is exactly the deterministic-vs-human split DOCS-REQ-006 describes. Also records the rename in the Unreleased CHANGELOG, which had rewritten historical entries in place but never logged the change itself. It is breaking twice over: the `action` declaration keyword replaces `intent` in surface syntax, and the canonical CBOR map key is now `actions`, which moved the reviewed Core and Target IR golden digests. Refreshes the documentation coverage matrix cell that was gated on "once #21 lands"; #21 and #20 both closed on 2026-06-24, so the first-success path is now an admitted gap rather than pending work. That cell was the only one in the matrix keyed to an issue number instead of a capability, per DOCS-REQ-005. docs-impact: documentation only; no behavior, schema, or fixture change. Verified with markdownlint (0 errors), cargo xtask contract-check (23 shelves), and cargo xtask target-ir-goldens --check (2 cases). BREAKING CHANGE: the `action` keyword replaces `intent` in Edict surface syntax, and the canonical CBOR action-map key is now `actions` in edict.core/v1 and edict.target-ir.artifact/v1. Previously published digests do not carry over.
CHANGELOG release headings recorded a planned biweekly schedule running
2026-06-24 through 2026-11-04, while every tag was actually cut between
2026-06-21 and 2026-06-30. The dates were never a typo: release-prep
writes "## [{tag}] - {target_date}" at scaffold time from
next_release_target_date(), and nothing back-filled the real date after
tagging. Keep a Changelog, which this file claims to follow, defines that
heading as the release date.
Realigns all four surfaces that carry the dates:
- CHANGELOG.md: 11 release headings
- docs/topics/release-process/policy.toml: 10 target_date fields
- docs/releases/*.md: 11 "Target date" lines
- xtask/src/tests.rs: the alpha_changelog_dates_match_release_policy
table and the nine release_policy_tracks_v0_N_boundary guards
The synthetic temp-repo fixtures in xtask/src/tests.rs keep their
original dates; their values are load-bearing for the +14 scaffolding
arithmetic and describe no real release.
target_date keeps its field name but now holds the actual publication
date, so RELEASE-REQ-008, its fixture oracle, and RELEASE-TP-004 are
restated to say so rather than describing a planned date.
Known gap, recorded in the release-process test plan:
next_release_target_date still adds 14 days to the last entry, which now
seeds 2026-07-14, already past. release-prep needs an explicit or
clock-derived date before the next release.
docs-impact: documentation and release-guard fixtures only; no library,
schema, or golden artifact change. Verified with cargo xtask verify
(full gate, 52s), 76 xtask tests, contract-check 23 shelves, and
markdownlint 0 errors.
…pies The release date guards were fragile and largely tautological. alpha_changelog_dates_match_release_policy asserted that CHANGELOG.md dates equalled policy.toml target_date values, but release-prep generates both from that one field. Two copies written from a single source always agree, including when the source is wrong, so the guard stayed green through four months of drift across all eleven releases and only failed once a human corrected one side by hand. It detected intervention, not incorrectness. The nine release_policy_tracks_v0_N_boundary tests (plus v0_2) matched substrings against the whole policy file rather than the release's own block. Verified: setting v0.3's target_date to 1999-01-01 left release_policy_tracks_v0_3_boundary passing, because v0.4 carried the same date string. Releases tagged on the same day share dates, so that is the normal case. They were also ~250 lines of frozen-history boilerplate, auto-written by a generator, asserting that a static file still contained strings someone typed. Replaces them with: - `cargo xtask release-dates`, which reconciles policy.toml, CHANGELOG.md, and docs/releases/*.md against `git for-each-ref refs/tags` -- the independent authority for when a release happened. Wired into `xtask verify`. Date contradictions fail; absent surfaces are reported as uncovered rather than failing an otherwise-correct history, since the earliest releases predate these surfaces. A clone without tags says it skipped instead of passing vacuously. - release_policy_blocks_are_structurally_complete, one data-driven test over parsed blocks, replacing eleven near-duplicates. - release_policy_block_parsing_scopes_fields_to_their_own_release, a regression guard pinning the 1999-01-01 false-pass. - reconcile_release_dates, a pure function over already-read inputs, with hermetic tests. cargo test needs no git tags, so CI's shallow checkout is unaffected. release-prep no longer scaffolds Rust test stubs or changelog date guard entries. Per-release scope and non-goal content is now reviewed rather than string-tested, matching the repo's own rule in docs/topics/documentation/test-plan.md that policy detail is not encoded as a Rust test; the ten affected requirement and test-case rows move to `policy` status accordingly. docs-impact: release-process README, test plan, and policy.toml updated with the new design and two recorded open gaps. Verified with cargo xtask verify (full gate, 9s), 69 xtask tests, and markdownlint 0 errors.
|
Important Review skippedToo many files! This PR contains 122 files, which is 22 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (122)
You can disable this status message by setting the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 66188d56ce
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| action_declaration: $ => seq( | ||
| 'action', | ||
| field('name', $.identifier), | ||
| $.parameter_list, | ||
| 'returns', | ||
| field('returns', $.type_reference), | ||
| repeat($.intent_clause), | ||
| repeat($.action_clause), |
There was a problem hiding this comment.
Regenerate Tree-sitter artifacts for action declarations
Regenerate every Tree-sitter consumer when changing this rule: the checked-in src/parser.c still recognizes intent/intent_declaration, while queries/highlights.scm still captures the "intent" token and an intent_declaration node. Consequently, editors using the generated parser reject the newly valid action syntax, and regenerating the parser alone makes the stale highlight query fail to compile because those symbols no longer exist. The current xtask test only searches the grammar source and capture names, so it does not exercise either failure.
AGENTS.md reference: AGENTS.md:L54-L61
Useful? React with 👍 / 👎.
| if report.drift.is_empty() { | ||
| let (count, gap_count) = (tags.len(), report.gaps.len()); | ||
| println!( | ||
| "release-dates: {count} tag(s) reconciled against git, {gap_count} uncovered surface(s)" | ||
| ); | ||
| return Ok(()); |
There was a problem hiding this comment.
Fail when required release surfaces become missing
Fail verification for missing surfaces except for an explicit allowlist of historical gaps. Currently, removing an existing release-notes file, its Target date: line, a changelog section, or a policy block only appends to gaps; because success depends solely on drift.is_empty(), cargo xtask verify still passes. This permits future regressions in the release signposts that the new reconciliation is intended to protect.
AGENTS.md reference: AGENTS.md:L298-L300
Useful? React with 👍 / 👎.
| SemanticErrorKind::MissingBudget => "MissingBudget", | ||
| SemanticErrorKind::MissingBasis => "MissingBasis", | ||
| SemanticErrorKind::DuplicateIntentClause => "DuplicateIntentClause", | ||
| SemanticErrorKind::DuplicateActionClause => "DuplicateActionClause", |
There was a problem hiding this comment.
Preserve the v1 duplicate-clause diagnostic identifier
Keep the wire code as DuplicateIntentClause when renaming the Rust variant, or version the diagnostic contract before changing it. For any source containing duplicate singleton clauses, this line changes the public edict.cli.diagnostic/v1 kind value to DuplicateActionClause; that breaks clients dispatching on the documented stable identifier and directly contradicts the adjacent invariant that a Rust variant rename must not alter the wire contract.
AGENTS.md reference: AGENTS.md:L141-L144
Useful? React with 👍 / 👎.
|
@codex review please CodeRabbit skipped this PR ( Note for the record: a file-count skip is not among the policy's enumerated The file count is inflated because commit |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 66188d56ce
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| provider_contract_pack(root, ProviderContractPackMode::Check)?; | ||
| provider_runtime_dependencies(root)?; | ||
| contract_check(root)?; | ||
| release_dates(root)?; |
There was a problem hiding this comment.
Reconcile the newly created tag before publication
For a release-prep merge, this call cannot validate the release being prepared: the checked .github/workflows/ci.yml never runs cargo xtask verify, .github/workflows/auto-release-tag.yml creates the tag only after that CI succeeds, and .github/workflows/release.yml publishes without invoking release-dates. Consequently, when the scaffolded target_date differs from the eventual tag date, the immutable tag and GitHub Release are published before this check can observe the discrepancy; run reconciliation after tag creation and before gh release create.
AGENTS.md reference: AGENTS.md:L82-L83
Useful? React with 👍 / 👎.
| - `lower_to_target_ir`, `TargetIrLoweringFacts`, `TargetIrArtifact`, | ||
| `TargetIrIntent`, `TargetIrStep`, `TargetLoweringReport`, stable | ||
| `TargetIrAction`, `TargetIrStep`, `TargetLoweringReport`, stable | ||
| `TargetLoweringStatus`, and stable `TargetLoweringFailureKind` values. |
There was a problem hiding this comment.
Restore the API names actually shipped in v0.9
When users consult these published v0.9 release notes, this now tells them that the release exposed TargetIrAction, although the Action rename is recorded under Unreleased and v0.9 actually shipped TargetIrIntent. The same retrospective substitution appears in other versioned release notes and released CHANGELOG.md sections, making historical documentation describe APIs and wire terminology that did not exist at those tags; retain the old names in published-release records and document the new names only in the release that introduces them.
AGENTS.md reference: AGENTS.md:L128-L129
Useful? React with 👍 / 👎.
| | T13 | OG-II proves silent last-write-wins merges create a permanent "action-recovery insufficiency floor"; only preserving conflict/authored acts as first-class objects avoids it | `agy:og-2-summary.md#29@25ff542`, `agy:observer-geometry-overview.md#38@25ff542` | 0.8 | The theoretical case for Edict's obstruction strands | | ||
| | T14 | Real Edict source exists in cross-project design docs: a `task.edit_document@1` action with pinned digests, `budget <=`, a `require jim.basisFresh(input.basis) else ... StaleBase` guard, effect-level `else` obstructions, and a typed `EditReceipt` | `EditObstruction` return union | `agy:agy/continuum-receipts.md#12-46@25ff542` | 0.8 | Matches the README's aspirational `createEntry` syntax family | |
There was a problem hiding this comment.
Preserve terminology from the pinned external evidence
These claims remain pinned to the unchanged external commit agy@25ff542, but the mechanical rename changes OG-II's previously cited ordinary term intent-recovery insufficiency floor and the cited source's intent declaration into action terminology without updating the evidence. Readers following the fixed citations therefore find sources that do not substantiate the report's new wording; preserve the external artifacts' terminology or refresh the citations to evidence that actually uses action.
AGENTS.md reference: AGENTS.md:L128-L129
Useful? React with 👍 / 👎.
Plain-English Walkthrough
TL;DR
Documentation upkeep that turned into three linked findings. The workspace-wide
Intent→Actionrename missed a topic shelf and was never recorded in thechangelog even though it breaks two contracts. Release dates across the repo
described a planned schedule rather than what actually shipped. And the tests
meant to prevent that second problem could not have caught it, because they
compared two generated copies of the same field against each other.
Contract-visible results: the
intent→actionbreak is now documented asbreaking for both surface syntax and the canonical CBOR ABI; all eleven release
dates match the tags that published them; and
cargo xtask release-datesreconciles those dates against
git for-each-ref refs/tagsinside the localgate. Net −555 / +237 lines in the guard rework.
No library, schema, or golden artifact behavior changes. No issues are closed by
this PR.
Walkthrough
What was already broken
Commit
9f1a11e0renamedIntenttoActionacross 108 files. It was a cleansubstitution — 905 insertions, 905 deletions — but it left three problems.
First,
docs/topics/target-ir/README.mddoes not appear in that commit's filelist at all [claim:target-ir-missed, confidence:1.00]. It carried six
occurrences of the old term and zero of the new one, so the shelf described a
Core intentthat no longer exists.docs/topics/target-ir/test-plan.mdwasworse in a subtle way: its evidence test names were renamed correctly while
the prose around them was not, leaving oracles that read "preserve … intent
input constraints" directly beside evidence named
action_constraints_and_budget_are_preserved_in_echo_span_ir.The local gate could not see this.
contract-checkverifies that evidence namesresolve to real test functions, that links resolve, and that fixture paths
exist — all of which still held, because the test names were correct. This is
the split
DOCS-REQ-006describes: deterministic checks for software facts,human review for reader-task quality.
Second, the rename was never logged. It rewrote historical changelog entries in
place but added no
Unreleasedentry, and it is breaking twice over. Thedeclaration keyword changed from
intenttoaction, so existing.edictsources no longer parse [claim:keyword-break, confidence:1.00]. The canonical
CBOR map key changed from
intentstoactionsin bothedict.core/v1andedict.target-ir.artifact/v1, which moved every derived digest[claim:abi-key-break, confidence:1.00].
That second break is easy to miss on review, and the reason is worth stating
plainly:
intentsandactionsare both seven characters, so the canonicalfixtures show
Bin 1478 -> 1478 bytesin the diff stat. Nothing in the bytecolumn signals a wire change. Only the
.sha256files do.Release dates described a plan, not a history
Every release heading in
CHANGELOG.mdwas months later than the tag thatpublished it [claim:date-drift, confidence:1.00]:
These were not typos.
release-prepwrites the heading from atarget_datefield at scaffold time, and nothing back-fills the real date after tagging. The
dates were a planned biweekly cadence; the releases shipped roughly four months
early. Keep a Changelog, which
CHANGELOG.mdclaims to follow, defines thatheading as the release date.
All eleven now match their tags, across four surfaces: the changelog headings,
the
target_datefields inpolicy.toml, theTarget date:lines indocs/releases/*.md, and thextaskguards that pinned them.Why the existing guard could not have caught it
alpha_changelog_dates_match_release_policyasserted that changelog datesequalled
policy.tomltarget dates. Both are generated from the same field, sothe assertion compared a copy against its own source
[claim:guard-tautology, confidence:0.95].
The diagram below shows why that arrangement is unfalsifiable: every arrow the
guard checked flows out of one origin, and the only independent record of when a
release happened was never consulted.
flowchart LR TD["policy.toml<br/>target_date"] -->|release-prep writes| CL["CHANGELOG.md<br/>heading date"] TD -->|release-prep writes| RN["docs/releases/*.md<br/>Target date:"] TD -.->|"old guard compared<br/>source against copy"| CL GIT["git tags<br/>actual publication date"] -.-> NEVER["not an input to<br/>any assertion"]Caption: One source, two copies, and an unconsulted authority
target_dateis written once at scaffold time byrelease-prep.never an input to any assertion.
Two copies written from one source always agree, including when that source is
wrong. The guard stayed green through four months of drift across all eleven
releases, and only failed once a human corrected one side by hand. It detected
intervention, not incorrectness.
The nine
release_policy_tracks_v0_N_boundarytests had a separate defect: theymatched substrings against the whole policy file rather than the release's own
block. Setting v0.3's
target_dateto1999-01-01leavesrelease_policy_tracks_v0_3_boundarypassing, because v0.4 carries the samedate string [claim:substring-false-pass, confidence:1.00]. Releases tagged on
the same day legitimately share dates, so this is the normal case rather than a
corner case. They were also roughly 250 lines of frozen-history boilerplate,
auto-written by a generator, asserting that a static file still contained
strings someone had typed.
The replacement
The new check compares recorded dates against the tags, so the authority is
outside the system that writes the dates.
flowchart LR GIT["git for-each-ref<br/>refs/tags"] --> R{{"reconcile_release_dates<br/>(pure)"}} POL["policy.toml<br/>target_date"] --> R CL["CHANGELOG.md"] --> R RN["docs/releases/*.md"] --> R R -->|date contradicts tag| D["drift → fails gate"] R -->|surface absent| G["gap → reported, passes"]Caption: Reconciliation inputs and the two outcome classes
driftand fails the gate.gap: reported on stdout, does not fail.The
drift/gapsplit is not cosmetic. Running the check for the first timeflagged that
v0.1.0-alpha.1has no policy block — which is true, and ishistory, because that release predates the structured policy. A check that fails
on correct history gets switched off, so absence is reported without blocking
while contradictions still fail.
Splitting the pure
reconcile_release_datesfrom the I/O inrelease_datesmatters for CI.
ci.ymlrunscargo test --workspacebehind anactions/checkoutwith nofetch-depth, which is a shallow clone without tags[claim:ci-shallow, confidence:0.95]. The unit tests therefore take already-read
inputs and need no git, while the git-dependent reconciliation runs in
cargo xtask verifyand in the release workflows, which do setfetch-depth: 0.The eleven per-release guards collapse into one data-driven test over parsed
blocks, plus a regression guard that pins the false-pass above. Per-release
scope and non-goal content is now reviewed rather than string-tested, matching
the repo's own rule that policy detail is not encoded as a Rust test; the ten
affected requirement and test-case rows move to
policystatus accordingly.That is a reduction in claimed coverage matching a reduction in actual
coverage that was always there.
alpha_changelog_dates_match_release_policy, hardcoded 10-row date tablecargo xtask release-dates, zero hardcoded datesrelease_policy_tracks_v0_N_boundary, file-globalcontains()release_policy_blocks_are_structurally_complete, block-scopedrelease_policy_block_parsing_scopes_fields_to_their_own_releasereconcile_release_dates+ 2 hermetic testsrelease-prepno longer scaffolds Rust test stubs or changelog date guardentries, and
policy.toml'sscaffold_outputslist drops the two removedentries.
Verification and known gaps
Both failure modes were negative-tested before the check was wired in. Corrupting
only the changelog date — the exact drift the old guard slept through — and
corrupting a single block's
target_dateeach fail with a message naming thetag and both dates [claim:new-check-catches, confidence:1.00]. The full local
gate passes [claim:gate-green, confidence:1.00].
Two gaps are recorded in the release-process test plan rather than left implicit:
next_release_target_datestill seeds the next value as last entry + 14days, which from the realigned history computes
2026-07-14— already past[claim:stale-seed, confidence:0.95].
release-prepneeds an explicit orclock-derived date. This now fails loudly at release time via
release-datesinstead of silently baking in another wrong date. Decidingthe replacement seeding is follow-up work, not part of this PR.
release actually shipped. That was equally true before; the removed tests
only checked that the strings were present.
Compatibility
The breaking changes described here landed in
9f1a11e0and are documented, notintroduced, by this PR. Because they remain unreleased, the next release should
carry them prominently: under 0.x a minor bump (
v0.12.0-alpha.1) conventionallycarries a break, and previously published digests do not survive the ABI key
change.
Appendix: Citations
claim:target-ir-missedgit show --stat 9f1a11e0 -- docs/topics/target-ir/README.md→ empty output; fixed atdocs/topics/target-ir/README.md#57@66188d56and#81@66188d56claim:keyword-breakcrates/edict-syntax/src/parser.rs#788@66188d56(self.expect_kw("action")?);git show 9f1a11e0^:crates/edict-syntax/src/parser.rsline 788 →self.expect_kw("intent")?claim:abi-key-breakdocs/abi/edict-core.cddl#13@66188d56(actions: { + tstr => core-action });docs/abi/edict-target-ir.cddl#26@66188d56;git show --stat 9f1a11e0 -- fixtures/core/canonical/bounded-hello.core.sha256→ 1 insertion, 1 deletionclaim:date-driftgit for-each-ref --format='%(refname:short) %(creatordate:short)' refs/tags→ v0.9.0-alpha.1 2026-06-28, v0.10.0-alpha.1 2026-06-29, v0.11.0-alpha.1 2026-06-30, against pre-change CHANGELOG headings 2026-10-07 / 2026-10-21 / 2026-11-04claim:guard-tautologyxtask/src/release_prep.rs#199@66188d56writes## [{tag}] - {target_date};xtask/src/release_prep.rs#251@66188d56writesTarget date: {target_date}; the removed guard compared those two outputsclaim:substring-false-passdocs/topics/release-process/policy.toml@7aae09af: rewriting only v0.3'starget_dateto1999-01-01leaves all assertions ofrelease_policy_tracks_v0_3_boundarysatisfied, because v0.4 supplies the expectedtarget_date = "2026-06-24"stringclaim:new-check-catchesrelease_date_reconciliation_reports_drift_and_gapsandrelease_date_reconciliation_accepts_dates_matching_their_tagsinxtask/src/tests.rs#2822@66188d56and#2875@66188d56;release_policy_block_parsing_scopes_fields_to_their_own_releaseat#2784@66188d56reconcile_release_dates, plus the pinned false-pass regression.claim:gate-greencargo xtask verify→ all stages pass in 9s, endingrelease-dates: 11 tag(s) reconciled against git, 1 uncovered surface(s);cargo test -p xtask→ 69 passed, 0 failed;markdownlint-cli2→ 0 errors-D warningsunder pedantic.claim:ci-shallow.github/workflows/ci.yml#28@66188d56usesactions/checkoutwith onlypersist-credentials: false;release.yml#30@66188d56andauto-release-tag.yml#44@66188d56both setfetch-depth: 0actions/checkoutdefaulting to depth 1 without tags; not independently executed in CI.claim:stale-seedxtask/src/release_prep.rs#383@66188d56(add_days_to_iso_date(&latest, 14)); latesttarget_dateafter realignment is2026-06-30, giving2026-07-14release-prepwould scaffold a release.