war-memory tighten hardening — #989 date validation + #992 target-aware verdict (v0.14.54) - #1061
Merged
Merged
Conversation
Round 1 found two root defects: the plan froze the Preflight stop instruction VERBATIM while that very region carried two claims the change falsifies, and the Purpose (a custom --target governs whether the preflight triggers) was unreachable because the live invocation passes no --target. Rounds 2-3 caught defects the patches themselves introduced - a self-contradictory surface enumeration with dangling labels, a non-discriminating grep that already passed, an orphaned fence lock no task claimed, a needle quoting a phrase that wraps a line break, and a false "these surfaces carry no crisp retired token" claim that would have left the default-flip failure mode open. Round 3 also found cross-plan collision no earlier round saw: lessons-learned-seed edits all three Task 1.2 files and is NOT campaign-serialized. Round 4 added the in-campaign CONTEXT.md contention (5 siblings) my own round-1 reversal created. 9 adjudication rows for args.adjudications. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… verdict (#1056) Closes the two code-verified holes in the `tighten` eviction ladder. #989 — `effectiveDate` took the lexicographic max over every date-SHAPED prose token, so a stray invalid (`2026-13-45`) or future (`2099-01-01`) stamp won and protected a lesson from eviction forever. Validation now lives inside `effectiveDate` itself (D1 — root cause, not the Floor-3 symptom): a token survives only if it round-trips through `Date.parse(token + 'T00:00:00Z')` (D2 — the engine's ISO parse IS the month/day range check) and does not post-date `now + FUTURE_SKEW_MS` (D3 — new module-private 48 h constant). Max over survivors; none surviving => null => the existing undated-PROTECTED path, so the fail-safe direction is preserved. Signature is additive, `effectiveDate(sources = [], { now = new Date() } = {})` (D4); `lessonRecord`'s call site stays sources-only (wall clock is correct at corpus-walk time). #992 — `tightenPlan` returned `buildProjection`'s verdict verbatim, so a custom `--target` below the advisory never governed whether the `/lessons-learned tighten` preflight triggered. The returned `verdict` is now the stricter of the two (D6/D7): `refuse` passes through; `warn` on the projection's own warn OR at `currentBytes >= target`; else `ok`. A loose target never suppresses the advisory warn. With the default `target = WARN_BYTES` this is byte-identical to today, so the default path is untouched. `buildProjection` is BYTE-UNTOUCHED — render-index and archive still read the pure advisory verdict. The Floor-3 `Number.isNaN(effMs)` guard is KEPT as a defense-in-depth backstop (D8 — `tightenPlan` is exported and takes caller-built records); its comment is reworded from behavior-claim to backstop. Comment sweep handled every retired token (`lexicographic max`, `Newest stamp anywhere`, `well-formed-but-invalid`) plus the section banner's "no parseable date anywhere". Tests are pure additions (77 lines, 0 deletions) — no existing test modified, skipped, or weakened. The prose-only recurrence floor test, the render-verdict trio and the cut-line `target: 2000` test all pass unmodified. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…alidated contract (#1056) Absorbs two audit Nit findings (advisory polish, comment-only): 1. [Nit] Test-file section banner still describes the pre-validation effectiveDate contract (war-memory.test.mjs:932) — the block banner read 'newest ISO date ... null when nothing parses', the OLD unconditional contract; after the diff the rule is 'newest VALID, non-future token; null when none survives'. The sweep was scoped to war-memory.mjs, so this test-file straggler fell outside the swept scope. 2. [Nit] Comment-lag (ADR 0025 duty 3): the effectiveDate test-section banner still states the pre-#989 contract in a file this diff touches — 'null when nothing parses' is no longer the whole null condition (null is also returned when every token parses but is beyond now + FUTURE_SKEW_MS), so the banner under-described two of the three tests in its block. Fix: extend the banner to 'newest VALID, non-future ISO date ...; null when no token survives validation (undated => PROTECTED)'. No assertion touched; existing tests stay byte-unmodified. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tract locks (#1057) `tightenPlan`'s printed `verdict` is now the stricter of the advisory projection verdict and the effective `--target` (#992), so every doc sentence reading the advisory line as the sole, fixed tighten trigger became false. Retire all eight enumerated OLD-reading surfaces and lock each one mechanically. SKILL.md (surfaces 1-6): the "never a `≤ target` reading" sentence → the stricter-of reading; the step-1 `--target` parenthetical no longer says "only for a different bound" (the flag also governs whether the pass triggers); the frontmatter description clause → effective target; the Phase-0 bullet → the *default* trigger; the verdict attribution → the effective read, not `buildProjection`'s own; the stop-rule appositive → "strictly under the effective target". The stop RULE itself (`ok` ⇒ report "nothing to tighten" and stop, no later step runs) survives semantically unchanged — the round-1 "verbatim" mandate is re-scoped to the contract, not the bytes. Live-flow threading: the step-1 fenced command now carries `${TARGET:+--target "$TARGET"}`, so an operator-supplied target actually reaches the preflight; with none supplied the flag drops out and the default run is byte-identical. CONTEXT.md (surfaces 7-8): the **Advisory line** and **Tighten pass** glossary entries no longer assert the advisory line is the sole trigger ("there is no third threshold" / "triggered at the advisory line") — it is the *default* trigger and exit target; a stricter `--target` becomes both for one invocation, and a looser one never suppresses the advisory warn. lessons-learned-doc-contract.test.mjs now loads CONTEXT.md (it read only SKILL.md and references/migration.md) and adds 5 tests / 11 assertions: six OLD-absent one per SKILL surface, two OLD-absent on CONTEXT (needles stop before the :1071→:1072 wrap), NEW-present on the reworded surface-1 sentence, NEW-present on the surviving stop rule, and a FENCE-SCOPED NEW-present on the threaded `--target` (a whole-region grep passes today via the parenthetical). All eleven temp-break-proven red.
…EN_TARGET (#1057) Absorbs two auditor-flagged Minor findings on the step-1 tighten preflight: 1. Step-1 \$TARGET relies on cross-invocation shell state; if it is unset the operator's target silently drops back to 17,000 B — the :+ expansion drops the flag when the variable is set in a separate Bash invocation from the fenced block, so the preflight binds at the default and reports "nothing to tighten" (the exact #992 silent failure mode). Fix: append the Phase 6/7 same-shell clause to the step-1 preamble ("set it in the same shell invocation as the command below, or substitute the literal figure — each command block runs in its own shell"). 2. Generic \$TARGET in the step-1 fence can inherit an ambient export, breaking the byte-identical default path — TARGET is a commonly-exported name (cargo/cross, Makefiles); a fresh shell inheriting it would silently thread --target x86_64-..., Number() -> NaN, and the printed plan comes back target: null instead of the 17,000 B default contract. Fix: rename to the namespaced \$TIGHTEN_TARGET in all three spots (preamble prose + fenced command). Lock (21) anchors on tighten-plan[^\n]*--target and is unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Task 1.3 (#1058): amend both origin lessons in place (never delete, temperature-is-location; D9) now that Task 1.1's effectiveDate validation + tightenPlan target-aware verdict landed on this integration tip. - effective-date-lex-max-over-all-date-shaped-prose-tokens-overprotects.md: description now leads with MITIGATED (#989, 2026-07-23); appended a dated MITIGATED note (code-verified against this task's rebased worktree) describing the UTC round-trip + FUTURE_SKEW_MS validation that closes the permanent-over-protection gap. - tighten-plan-target-flag-does-not-lower-fixed-warn-bytes-preflight-stop.md: description now leads with RESOLVED (#992); appended a dated RESOLVED note describing tightenPlan's now target-aware verdict (stricter of the advisory read and --target, D7). The existing Status paragraph's historical quote of the retired SKILL.md sentence is left untouched as a provenance-dated record, with a short disclaimer pointing at the superseding note. Both rewritten descriptions stay at/under their current byte length (measured as the YAML value): #989 165B <= 181B, #992 97B <= 117B. Metadata keys, provenance, and keywords are unchanged. `node skills/_shared/war-memory.mjs lint docs/learnings/` exits 0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ver residual (task 1.3 --ace) Auditor absorb findings applied: 1. [Minor] #992 lesson's H1 title and two body paragraphs still assert the now-false claim as live; the added 'historical record' parenthetical is scoped to the Status paragraph only — a reader/retrieval hit that opens the file reads a false live claim before reaching the RESOLVED note. Fix: H1 now leads with 'RESOLVED —' (matching the binding exemplar's convention), and the 'What'/'The gotcha' bold lead-ins now carry '(as shipped 2026-07-21, superseded by #992 — see below)'. Slug/name/ metadata unchanged; prose only. 2. [Nit] #989 MITIGATED note omits the deliberate 2026-02-31 rollover residual that the implementation's own comment records — since the lesson's original advice was literally 'validate month <= 12 && day <= 31' and the amendment is MITIGATED precisely because residuals remain, omitting it invites over-trusting the validation later. Fix: one clause added to the 'What's still true' paragraph — a day-overflow token such as 2026-02-31 still survives the UTC round-trip (rolls over to early March), a bounded residual accepted by design. Gate: war-memory lint clean; node --test 886/886 pass. Refs #1056 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…26-07-22-war-memory-hardening
…eep left behind The phase-close coherence sweep was skipped this phase, so two `absorb`-disposition findings fell through to the follow-up list. Both re-confirmed at the landed tip and fixed here rather than deferred: - war-memory.test.mjs: two test titles still stated the pre-#989 contract while the section banner right above them had been updated to the validated one. Titles only — no assertion, fixture, or signature touched. - #989 origin lesson: the H1 and the "What" lead-in asserted the retired behavior in present tense with no supersession marker, while the #992 sibling got exactly those markers in the same diff. Mirrors the sibling's shape; frontmatter untouched. Gate: 891/891 JS + 26/26 shell green; war-memory lint clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… lint absent from gate artifacts Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bump all four version slots in lock-step to the next free patch above the live integration base: plugin.json `version`, marketplace.json `metadata.version` and `plugins[0].version`, and the README `## Status` line (replace-in-place, no badge). All four slots read 0.14.53 at the phase base — the global max across every ref — so 0.14.54 is the next free patch, resolved from the four slots as they stand in the rebased tree (version-slots.test.mjs is the arbiter; plan v-literals are non-authoritative). Status blurb (additive/precise): `effectiveDate` now rejects invalid-shaped and beyond-skew future date tokens (fail-safe preserved — none surviving ⇒ undated ⇒ protected); `tighten-plan`'s `verdict` is now the stricter of the advisory line and the effective `--target`, so the preflight can bind at a stricter `--target` while a looser one moves only the exit target, never the trigger. `buildProjection`, `render-index`, and `archive --candidates` semantics untouched. Prior release prose left as-is. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…26-07-22-war-memory-hardening
… lesson (cross-campaign) Servitor wrap-up recorded a 16th recurrence of the stale-session-worktree hazard, now spanning four unrelated phase wrap-ups across multiple campaigns (D1 in-place update, no new file). Task 2.1 (version bump) itself carried no durable gotcha. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jul 23, 2026
This was referenced Jul 24, 2026
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.
Campaign plan 6 of 9 —
2026-07-22-run-resilience-and-hardening. Stacked (ADR 0011) ondev/2026-07-22-test-floor-target-repo(plan 5, PR #1052). Merge bottom-up: this PR merges after #1052.Closes the two code-verified holes in the
/lessons-learned tighteneviction ladder.What changed
#989 —
effectiveDatenow validates the date tokens it scrapes from lesson prose. A date-shaped match is kept only if it (1) round-trips through a UTC parse — an invalid stamp like2026-13-45is dropped — and (2) lands no more than 48 h (FUTURE_SKEW_MS) past the current clock — a stray far-future token like2099-01-01no longer counts. Fail-safe direction preserved: when no token survives, the lesson reads undated and stays protected, exactly as before. Validation is additive via an{ now }options arg; thelessonRecordcall site is unchanged.#992 —
tighten-plan'sverdictis now the stricter of the advisory line and the effective--target. A sub-advisory--targetmakes the preflight bind there instead of silently deferring to the fixed 17,000 B advisory.buildProjectionis byte-untouched — onlytightenPlan's returned verdict is overloaded; the default path is provably byte-identical.Doc-retire (default-flip discipline): the ratified fixed-advisory prose is retired across six enumerated
SKILL.mdsurfaces + twoCONTEXT.mdglossary entries, each locked OLD-absent (not merely NEW-present) inlessons-learned-doc-contract.test.mjs, which now also loadsCONTEXT.md. Both origin lessons amended in place with dated MITIGATED (#989) / RESOLVED (#992) notes.Phases
87f42efc74a1fcGate at land: 891/891 JS + 26/26 shell,
war-memory lintclean,version-slots.test.mjs3/3.Follow-up filed
--target(no value) flips the tighten verdict to warn and pre-selects every eligible lesson #1059 — a bare--target(no value) resolves toNumber(true)=1, so the now-target-aware verdict always readswarnand the strike list pre-selects every eligible lesson. Reproduced live; bounded blast radius (one operator approval, archive is a move not a delete) → Minor, filed not blocked.Unexecuted backstops (AI-declared, ADR 0014)
tightenpost-releaseFUTURE_SKEW_MS(48 h) vs real UTC-midnight-vs-local-date skewnowtighten-plan/renderruns🤖 Generated with Claude Code