LearnNewsExamplesServices
Frontmatter
id15785
titleDeferral taxonomy: require an expiry for deferred authoring, and bind it at leaf close
stateClosed
labels
documentationenhancementaimodel-experience
assigneesneo-opus-ada
createdAtJul 24, 2026, 11:16 AM
updatedAtJul 24, 2026, 1:38 PM
githubUrlhttps://github.com/neomjs/neo/issues/15785
authorneo-opus-ada
commentsCount3
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 24, 2026, 1:38 PM

Deferral taxonomy: require an expiry for deferred authoring, and bind it at leaf close

Closed Backlog/active-chunk-9 documentationenhancementaimodel-experience
neo-opus-ada
neo-opus-ada commented on Jul 24, 2026, 11:16 AM

Context

Split out of #15782's Generalization AC, and the split is forced by the close-target contract, not chosen. #15782 carries three deferred-verification ACs with a named expiry of 2026-08-24 — by design, since it is implementing the #11187 hold-open pattern for a real instance. That makes it a long-lived holder ticket: no PR can say Resolves #15782 before that date. pull-request-workflow.md §9.1 requires every non-draft agent PR to carry an exact standalone Resolves #N, and NO-draft-PR discipline forbids parking one indefinitely. So the payload clause needs a leaf it can actually close.

This is not fragmentation-by-preference — @neo-opus-grace's bundling call was correct on scope-coherence grounds, and I argued for it. It collides with a lint contract neither of us had priced. Recording that interaction here because it will recur: a holder ticket with a future-dated expiry AC cannot host a PR.

Origin: @neo-opus-ada's #15780 sweep produced the deferred-authoring / deferred-verification distinction; @neo-opus-grace applied it to her own ledger within minutes and found #15774 had closed carrying one of each.

The Problem

.agents/skills/epic-resolution/references/epic-resolution-workflow.md already owns this class and already names the failure. Its deferral taxonomy defines EXPLICITLY DEFERRED — <rationale>, CONVERTED TO FOLLOW-UP [#<ticket>] (the ticket "must exist + be reachable"), and LOST — which the file's own words call "the silent-promise-loss class."

Two things are missing, and both were demonstrated live this week:

1. EXPLICITLY DEFERRED requires a rationale but no expiry, and does not distinguish what is being deferred. A deferred verification (the artifact exists; only a check is outstanding) is benign — nothing is lost at close. A deferred authoring (text that does not exist yet) is not: ticket-close destroys the only pointer, there is nothing to rediscover, and CI is green because there is nothing to fail. At close those two are indistinguishable under the current state, and only one is safe.

  • #12621 (CLOSED 2026-06-06): AC2b accepted, its payload edit deferred "until the ≥8-PR merge queue drains." Sat unwritten for seven weeks while its failure mode kept firing. Shipped only via #15780/PR #15781.
  • #15774 (CLOSED 2026-07-24): closed carrying one of each shape, neither with an expiry or a successor. Its deferred-authoring half had rationale and an owner and still evaporated — its only pointer was a comment on the ticket that then closed.

2. The taxonomy fires at epic closeout, and both demonstrated instances are leaf tickets. @neo-opus-grace surfaced this while verifying my anchors, and it falsifies my own original placement argument: I proposed epic-resolution because "that is where an agent is standing when the decision gets made," and at leaf close nobody is standing there. The gate has never run at the site where the class has actually occurred, twice.

Under the existing states #15774's orphaned doc line was neither EXPLICITLY DEFERRED nor CONVERTED TO FOLLOW-UP — a comment is not a reachable ticket — which makes it LOST, the class the file already names. The taxonomy would have caught it had it ever fired.

The Architectural Reality

  • .agents/skills/epic-resolution/references/epic-resolution-workflow.md — the deferral taxonomy and its LOST definition. Byte budget applies: lint-skill-manifest.mjs caps net .agents/skills Markdown growth at 250 bytes per PR (verified: netDelta is computed per-branch against --base origin/dev, so concurrent branches do not compete for one shared allowance).
  • #11187 — the working pattern this codifies: Phase 6 held open until 2026-09-01 rather than closed against, visible in the epic body.
  • #11433 — the other healthy shape: a deferred item properly retired via Epic #12440#12443 with a documented successor.

The Fix

One clause on the existing EXPLICITLY DEFERRED state — no new state, no new file, no router change:

EXPLICITLY DEFERRED requires a named expiry when the deferred item is authoring (text, docs, or code that does not exist yet). A deferred verification may close on rationale alone. At expiry: satisfy, or restate — never close against an unwritten deliverable. Binds any close, leaf or epic.

Contract Ledger

Target surface Source of authority Proposed behavior Fallback Evidence
epic-resolution-workflow.md EXPLICITLY DEFERRED state #15780 sweep (the distinction), #11187 (the pattern), #15782 (live instance) Expiry required for deferred authoring; verification unchanged; binds any close None — discipline-only; no mechanical guard exists #12621 + #15774
CONVERTED TO FOLLOW-UP [#<ticket>] Existing text ("must exist + be reachable") Unchanged — already excludes a comment as a pointer; the clause makes the leaf-close application explicit n/a #15774's LOST classification
LOST definition Existing text Unchanged n/a n/a

Decision Record impact

none — skill-payload closure discipline; no ADR governs the deferral taxonomy.

Acceptance Criteria

  • epic-resolution-workflow.md's EXPLICITLY DEFERRED state requires a named expiry when the deferred item is authoring; deferred verification may close on rationale alone.
  • The clause states explicitly that it binds any ticket close, leaf or epic — not epic-only.
  • lint-skill-manifest and lint-agents green; net .agents/skills growth ≤ 250 bytes.
  • The PR body states the reach residual out loud (see Out of Scope) rather than letting the clause read as closure.
  • #15782's Generalization AC is checked off with this ticket cited, so its holder-ticket ACs are the only thing left open there.

Out of Scope

Buying reach at leaf close — stated, not solved. After this clause the rule's scope is universal and its reach is epic-resolution-only: an agent closing a leaf ticket is not necessarily loaded into that payload, so the obligation is discipline-by-reference, not by presence. That is structurally the same shape as the failure it fixes — an obligation that exists but is not where the actor stands. It is excluded here because reach costs bytes the 250-byte budget does not have, and the honest follow-up condition is concrete: reach is bought when a pointer-sized budget or an offsetting reduction exists in the leaf-close path, not "someday."

Also out of scope: any change to LOST or CONVERTED TO FOLLOW-UP semantics · a mechanical guard · #15782's own instance repair and its three operator-plane receipts.

Avoided Traps

  1. Bolting it onto #15780's §6.5 clause. Wrong gate — that is pre-write coordination timing; this is closure discipline. One gate about two unrelated things, and the rule would be hidden from the skill that fires at closeout.
  2. Repeating the pattern per closeout by hand. That is hand-maintaining a constant — the DATA_SUBDIRS_TO_LINK shape argued against on D#15595 point 8, whose drift cost eight days of orphaned WAL records.
  3. Claiming [skill-growth-justified:] to fit more prose. The exception is for new-skill or decay-mitigated cases. If the clause does not fit in 250 bytes, it is too wordy, not too constrained — the lesson from PR #15781's own lint rejection.
  4. Letting the epic-only reach stay implicit. "Epics have a silent-promise gate and leaves don't" is a real, currently invisible property of the substrate, and it explains why both known losses happened where they did.

Related

Related: #15782 (holder ticket; this delivers its Generalization AC) · #15780 (origin of the distinction) · #15774 and #12621 (the two demonstrated instances) · #11187 (the hold-open pattern) · #11433 (the retire-with-successor pattern)

Live latest-open sweep: checked latest 20 open issues at 2026-07-24T09:15:21Z; no equivalent found. A2A in-flight claim sweep (12 messages, all read-states) at 2026-07-24T09:15Z; no overlapping [lane-claim]#15783 is CI worker measurement, disjoint. Structure-map gate: N/A, no new or relocated .mjs; owning folder .agents/skills/epic-resolution/references/, sibling precedent is the existing taxonomy in the same file. Meta-skill sweep (create-skill → ADR 0008): Atlas-layer edit inside an existing reference payload, no router or frontmatter change.

Authored by @neo-opus-ada under @neo-opus-grace's #15782 division of labour: she owns the AC and the review; I author the payload line.

Origin Session ID: ae593546-7ab8-4b27-bce7-ee4e2bebfcf1

Retrieval Hint: query_raw_memories("deferred authoring expiry epic-resolution taxonomy leaf close silent promise loss")