rvlib-shipkit 0.22.0 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.22.1
4
+
5
+ - **Fix: the cache stamp is baked in at RUN time, replays print it verbatim.** 0.22.0 annotated only the REPLAY, so a fresh run and a cache hit rendered different strings and STATUS.md still diffed on every alternation (his catch, the second one on this line). A TTL clean pass now writes "(cached at <stamp> until <stamp>)" into the line once, live output and every replay are byte-identical, and the line changes only when a re-validation happens. Proven: fresh-then-cached runs produce a zero-diff STATUS body.
6
+
3
7
  ## 0.22.0
4
8
 
5
9
  - **Fix: the machine-row auto-commit could not see STATUS.md.** The git helper trims its whole output, so the FIRST porcelain line loses its leading space and the old column-3 slice read "TATUS.md", making the preflight silently decline the exact dirt it was built to eat. `dirtyPathList` parses status prefixes robustly now (renames and quoted paths included, regression-tested on the trimmed-first-line case), and a decline is never silent: the preflight names the non-machine paths it refused.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rvlib-shipkit",
3
- "version": "0.22.0",
3
+ "version": "0.22.1",
4
4
  "description": "All-in-one repo companion: ci gate (task DAG), auto-discovered health checks, release-contract fulfillness, asks queue, md-wiki tools, asset atelier, live tui",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -143,13 +143,14 @@ export class CheckSuite {
143
143
  && entry != null && entry.version === r.version && entry.key === key
144
144
  && this.now() - entry.at < r.ttlMs && this.now() >= entry.at
145
145
  if (fresh) {
146
- // absolute stamp, never "Xm ago": a relative age re-renders on
147
- // every run and turns committed STATUS.md checkpoints into
148
- // noise diffs (his call 2026-08-05). The line now changes only
149
- // when the cache actually refreshes.
150
- const lines = entry.lines.map((l, i): Line => (i === 0 ? { ...l, text: `${l.text} (cached ${fmtStamp(entry.at)})` } : l))
151
- out.push(...lines)
152
- this.onResult?.(r.name, { lines, status: 'pass', cached: true }) // only clean passes are cached
146
+ // the stamp was baked in when the check RAN (below): a replay
147
+ // prints the stored lines VERBATIM, so the live run and every
148
+ // later replay render the same string, and the line changes
149
+ // only when a re-validation happens (his call 2026-08-05,
150
+ // second round: annotating replays but not live runs still
151
+ // diffed on every fresh-vs-cached alternation)
152
+ out.push(...entry.lines)
153
+ this.onResult?.(r.name, { lines: entry.lines, status: 'pass', cached: true }) // only clean passes are cached
153
154
  continue
154
155
  }
155
156
  const t = new CheckCtx(this.toolPaths)
@@ -160,14 +161,18 @@ export class CheckSuite {
160
161
  else if (e instanceof ToolUnresolved) t.note(`${r.name} skipped (${e.message})`)
161
162
  else t.fail(`${r.name} errored (${String(e).slice(0, 200)}) — network down, or a bug in this check`)
162
163
  }
163
- out.push(...t.lines)
164
- this.onResult?.(r.name, { lines: t.lines, status: t.failed ? 'fail' : t.warned ? 'warn' : 'pass', cached: false })
164
+ // a skip line is an UNKNOWN, not a clean pass — replaying
165
+ // "registry unreachable" for a TTL asserts a dead network as
166
+ // fact long after it recovered
167
+ const cacheable = r.ttlMs > 0 && !t.failed && !t.warned && !t.lines.some((l) => l.kind === 'skip')
168
+ const lines = cacheable
169
+ ? t.lines.map((l, i): Line => (i === 0 ? { ...l, text: `${l.text} (cached at ${fmtStamp(this.now())} until ${fmtStamp(this.now() + r.ttlMs)})` } : l))
170
+ : t.lines
171
+ out.push(...lines)
172
+ this.onResult?.(r.name, { lines, status: t.failed ? 'fail' : t.warned ? 'warn' : 'pass', cached: false })
165
173
  if (t.failed) anyFail = true
166
174
  if (r.ttlMs > 0) {
167
- // a skip line is an UNKNOWN, not a clean pass — replaying
168
- // "registry unreachable" for a TTL asserts a dead network as
169
- // fact long after it recovered
170
- if (!t.failed && !t.warned && !t.lines.some((l) => l.kind === 'skip')) { cache[r.name] = { version: r.version, key, at: this.now(), lines: t.lines }; cacheDirty = true }
175
+ if (cacheable) { cache[r.name] = { version: r.version, key, at: this.now(), lines }; cacheDirty = true }
171
176
  // a WARN/FAIL evicts the stale pass — a later run must re-probe,
172
177
  // not replay an ok recorded before the breakage
173
178
  else if (entry != null) { delete cache[r.name]; cacheDirty = true }