diff --git a/memory/MEMORY.md b/memory/MEMORY.md index c1a5d33a4..6b3d632d9 100644 --- a/memory/MEMORY.md +++ b/memory/MEMORY.md @@ -4,6 +4,7 @@ **📌 Fast path: read `CURRENT-aaron.md` and `CURRENT-amara.md` first.** These per-maintainer distillations show what's currently in force. Raw memories below are the history; CURRENT files are the projection. (`CURRENT-aaron.md` refreshed 2026-04-28 with sections 26-30 — speculation rule + EVIDENCE-BASED labeling + JVM preference + dependency honesty + threading lineage Albahari/Toub/Fowler + TypeScript/Bun-default discipline.) +- [**actions/cache paths mutually exclusive with git ls-files — silent-clobber bug class (Aaron 2026-05-03 "make it not lucky next time")**](feedback_actions_cache_paths_mutually_exclusive_with_git_ls_files_silent_clobber_class_aaron_2026_05_03.md) — Cache hit OVERWRITES checked-out source content; PR edits silently revert; CI tests OLD content but reports as PR's new state. Surfaced via CircuitRegistration B-0180 fix passing locally + failing CI. Carved-sentence rule + `audit-ci-cache-paths.ts` + CI lint gate prevent recurrence. - [**Chat is assertion-channel, not fact-channel — push-back-with-evidence is the discipline (Aaron 2026-05-03)**](feedback_chat_is_assertion_channel_not_fact_channel_push_back_for_evidence_aaron_2026_05_03.md) — Chat-claims (maintainer's, architect's, external-AI's) are assertions needing evidence to elevate to architectural fact. *"when i speak i'm making assertions, that's the best way to describe this chat channel"* + push-back-required-even-when-he-asserts. Triggered by #1385 echoing "maybe" as architectural fact. - [**Carved sentences + specialized index required — memories alone unreliable retrieval (Aaron 2026-05-03)**](feedback_carved_sentences_plus_specialized_index_required_memories_alone_unreliable_aaron_2026_05_03.md) — Memory file ≠ working memory. Empirically self-demonstrated: Otto authored speculative-vs-frontier memo, then ~6h later defaulted to the framing it corrects. CLAUDE.md / AGENTS.md / equivalent are the auto-loaded retrieval index for the beacon-safe layer. - [**Mirror-vs-beacon-safe register architecture — publication boundary as backpressure (Claude.ai 2026-05-03 verbatim packet)**](../docs/research/2026-05-03-claudeai-mirror-vs-beacon-safe-publication-boundary-as-backpressure.md) — Mirror = internal/named-agent register (overgenerates); beacon-safe = external/end-user-persona register (conversion-pruned). Publication discipline IS the gate; no separate mechanism needed. Diamond framing: mirror=solution, beacon-safe=crystal, conversion=pressure. Multi-AI BFT review = conversion-quality control. diff --git a/memory/feedback_actions_cache_paths_mutually_exclusive_with_git_ls_files_silent_clobber_class_aaron_2026_05_03.md b/memory/feedback_actions_cache_paths_mutually_exclusive_with_git_ls_files_silent_clobber_class_aaron_2026_05_03.md new file mode 100644 index 000000000..80c6e554b --- /dev/null +++ b/memory/feedback_actions_cache_paths_mutually_exclusive_with_git_ls_files_silent_clobber_class_aaron_2026_05_03.md @@ -0,0 +1,130 @@ +--- +name: actions/cache paths are mutually exclusive with git ls-files — silent-clobber bug class +description: Carved-sentence discipline rule. actions/cache paths must NOT overlap git-tracked files. Cache hit OVERWRITES checked-out source content with cached versions; PR edits silently revert; CI tests OLD content but reports as PR's new state. Surfaced empirically via CircuitRegistration Safety fix passing locally + failing CI; root-caused by verify-then-claim sweep. +type: feedback +--- + +**Rule:** `actions/cache` paths in `.github/workflows/*.yml` MUST be +mutually exclusive with `git ls-files`. Cache only DERIVED files +(downloaded jars, built artefacts, user-home tool state), never +source-controlled content. + +**Bug-locus disambiguation (Aaron 2026-05-03):** +This is a **usage bug in our workflow configuration**, not a bug in +`actions/cache` or GitHub Actions. The cache action does exactly +what its docs promise: restores cached files at the configured +paths, overwriting whatever's there. We asked it to cache a path +that contained source-controlled files — it did. The fix is on our +side: narrow the cache path so it doesn't overlap source-controlled +content. A reasonable upstream feature request (warning when cache +path overlaps with checked-out git content) would be an +enhancement, not a bug fix, since the existing behavior is +documented. + +**Why this is load-bearing:** + +When `actions/cache` restores on a cache hit, it OVERWRITES the +freshly-checked-out source files with the cached versions. If the +cache path is a directory and that directory contains source- +controlled files, those files revert to whatever was in the cache +when it was first warmed. + +**Failure mode (silent + invisible):** + +1. PR modifies a source-controlled file under a cached path +2. CI checkout brings in the PR's new version +3. `actions/cache` step restores → OVERWRITES with cached old version +4. Build / test runs against OLD content +5. Test report claims PR's new content was tested ✓ +6. PR merges based on stale test results + +The bug only surfaces when the PR's edit introduces a NEW operator +referenced by a config (or analogous fail-loud condition) — because +then the silently-restored old content FAILS the new check, instead +of falsely-passing on stale state. Discovery-by-luck class. + +**Triggering case (2026-05-03):** + +CircuitRegistration `Safety` invariant fix (B-0180): + +- Local: `Model checking completed. No error has been found.` + 3538 states / depth 14 +- CI: `Error: The invariant Safety specified in the configuration + file is not defined in the specification.` + +Diff: local ran the new spec; CI's `actions/cache@v5` step cached +`tools/tla` (whole dir, including `specs/`) and restored old content +that DIDN'T have the `Safety` operator. CI tested the OLD spec. + +**How to apply:** + +1. **At workflow-author-time:** when adding an `actions/cache` step, + the path MUST be specific to derived files. If the natural-feeling + path is a whole directory, ask: does that directory contain ANY + source-controlled file? If yes, narrow. + +2. **At verify-then-claim-time:** when a CI test fails on a config + that works locally with the same toolchain version + same input, + first hypothesis: "is CI testing the same content I'm testing?" + Compare the failure error against pre-PR state. If the failure is + "old behavior", suspect cache clobber. + +3. **Structurally enforced:** `tools/hygiene/audit-ci-cache-paths.ts` + parses every `actions/cache` `path:` and flags any overlap with + `git ls-files`. Wired as CI lint via + `.github/workflows/ci-cache-paths-lint.yml`. Future cache-clobber + bugs cannot land silently — this gate fails the workflow with + self-diagnosing output. + +**Carved sentence (for retrieval):** + +> *"actions/cache paths are mutually exclusive with `git ls-files` — +> cache only DERIVED files (downloaded jars, built artefacts, user- +> home tool state), never source-controlled content."* + +**Composes with:** + +- **Otto-272 DST-everywhere + Otto-281 DST-exempt-is-deferred-bug:** + cache-clobber is a non-determinism source (CI tests different + content than local); same discipline class as flaky tests. +- **Verify-then-claim:** the failure mode is silent-pass; verify- + then-claim ("does CI actually run what I think it runs?") is the + catch. +- **Test-fidelity contract:** the math-proofs honest assessment's + A-grade rubric requires "Runs in CI on every commit" — but that + presupposes CI runs the COMMIT'S content, not cached content. + Cache clobber breaks the rubric silently. +- **CI-on-CI audit pattern:** the same shape applies to other + meta-properties of CI workflows (e.g., timeouts not being too + short to actually run the work; required-status-checks matching + the workflow's job names; etc.). Future audits in this family + follow the cache-paths audit's pattern: parse YAML, check against + invariant. + +**Tooling lineage:** + +- `tools/hygiene/audit-ci-cache-paths.ts` — the audit +- `.github/workflows/ci-cache-paths-lint.yml` — the CI gate +- `.github/workflows/gate.yml` (post-fix narrowing) — the canonical + pattern (path: jar files only, not directories) +- `.github/workflows/low-memory.yml` (post-fix narrowing) — same + +**Future-Otto reference:** + +When tempted to write `path: tools/