Skip to content

chore: delete stale harness artifacts the rebuild left behind - #679

Merged
thomasluizon merged 4 commits into
mainfrom
chore/delete-stale-harness-artifacts
Aug 4, 2026
Merged

chore: delete stale harness artifacts the rebuild left behind#679
thomasluizon merged 4 commits into
mainfrom
chore/delete-stale-harness-artifacts

Conversation

@thomasluizon

Copy link
Copy Markdown
Owner

Staleness audit of every one of the 2,214 tracked files in orbit-ui-mobile after the 2026-08-04 harness rebuild (#676). Fourteen files removed, two files had dead reference lines cut. Everything I considered and kept is listed with the reason, including the one finding I deliberately did not act on.

Also folded in the unpushed local commit chore: ignore agent scratch files by shape, not by name, since it gates the same class of file this sweep hunted. Nothing was stashed and nothing was discarded.

Deleted

1. Six baselines and snapshots whose reader no longer exists

File Its reader Reader on disk?
tools/lockstep-declarations.json tools/check-lockstep.mjs no
tools/context-budget.json tools/check-context-budget.mjs no
tools/on-demand-budget.json tools/check-context-budget.mjs no
tools/archaeology-baseline.json tools/check-archaeology.mjs no
tools/required-gates.json tools/check-required-gates.mjs no
.claude/linear-team-labels.json the tier-labels job in guards.yml no
$ ls tools/ | grep -Ei 'lockstep|archaeo|required-gates|calibration|context-budget'
(nothing but the .json data files themselves)

required-gates.json names its own missing reader in its note field: "tools/check-required-gates.mjs is the reader." That file does not exist.

Two of them had already drifted into nonsense, which is what a baseline nobody reads does:

tools/context-budget.json     says CLAUDE.md is 10,504 bytes.  Actual: 6,654.
tools/on-demand-budget.json   says orchestrate/SKILL.md is 53,533 bytes.  Actual: 19,024.

.claude/linear-team-labels.json is a 2026-07-28 Linear label snapshot listing tier:cheap, tier:deep and worker:sonnet. tools/lib/orchestrator-config.mjs:82 says outright: "The tier:cheap / tier:deep label machinery is gone." Zero references to the file across all three repos and the brain vault.

2. skills-lock.json

Empty stub. Entire content:

{ "version": 1, "skills": {} }

The calibration job that maintained it was deleted by the rebuild. Zero references anywhere.

3. Two export {} mocks

apps/mobile/test-mocks/shared-empty.ts and apps/mobile/test-mocks/shared-types.ts. Each file is one line, export {}. I checked every mock in that directory against the alias map:

$ for f in apps/mobile/test-mocks/*.ts; do
    grep -q "test-mocks/$(basename $f)" apps/mobile/vitest.config.ts || echo "NOT ALIASED: $f"
  done
NOT ALIASED: shared-empty.ts
NOT ALIASED: shared-types.ts

Those two, and only those two, out of 25. A repo-wide grep for either name returns nothing. The other 23 are all aliased and stay. Mobile's 247 test files still pass.

4. Five ORB-116 artifacts untracked (not deleted from disk)

Class: tracked and gitignored at the same time. This is the contradiction the audit was asked to resolve rather than leave.

$ git ls-files -i -c --exclude-standard
.artifacts/surfaces/ORB-116-render-critique.md
.artifacts/surfaces/route-about--default--dark--en.png
.artifacts/surfaces/route-about--default--dark--pt-BR.png
.artifacts/surfaces/route-about--default--light--en.png
.artifacts/surfaces/route-about--default--light--pt-BR.png

$ git check-ignore -v --no-index .artifacts/surfaces/ORB-116-render-critique.md
.gitignore:72   .artifacts/

I untracked them and kept the ignore rule, rather than dropping the rule. The rule is correct: .artifacts/ is the output directory tools/capture-surfaces.mjs regenerates on every visual run, and RENDER-CORRECTNESS.md:21 and :36 both describe it as output. These five were committed once by #636 and have been both tracked and ignored ever since. Nothing anywhere references them; a repo-wide grep for "ORB-116" finds only the critique file naming itself. The files stay on disk untouched.

5. Dead reference lines in two files

.github/workflows/guards.yml. Its header comment listed thirteen jobs. The file defines five. Removed the eight that do not exist: context-budget, archaeology, frontmatter, harness, lockstep, calibration, tier-labels. The same comment claimed four jobs carry a label escape hatch and then named five labels; three of those (context:reseed, calibration:reseed, coverage:reseed) have no consuming job left anywhere in .github/workflows/. Corrected to the two that are real.

$ python -c "import yaml; print(list(yaml.safe_load(open('.github/workflows/guards.yml'))['jobs']))"
['dashes', 'copy', 'ratchet', 'parity', 'expo-pin']

.claude/skills/second-opinion/SKILL.md:91. Described the auto-fire condition as "in an unattended --sleep run". The --sleep flag was deleted by the rebuild. The skill's own frontmatter description already reads "in unattended runs", so the body had drifted from its own header. Cut the flag name only.

Considered and kept, with what I ruled out

The one you should look at. apps/web/components/ui/mono-toggle.tsx and apps/mobile/components/ui/mono-toggle.tsx have zero importers. The only places either path appears are coverage exclusion lists (apps/web/vitest.config.ts:44, apps/mobile/vitest.config.ts:133, sonar-project.properties:58), which is evidence it was never tested because it was never used, not evidence of use. I did not delete it: MonoToggle is defined in the Figma handoff at design/handoff/orbit/project/orbit-app-components.jsx:161 and appears as the standard settings toggle across eight handoff screens (chat, subs, overlays, detail-create, extras). Deleting an implemented design system primitive is a design decision, not a staleness one, and .claude/rules/core.md rule 5 puts design system scope in your hands rather than mine. What would settle it: your call on whether MonoToggle is still the intended settings toggle. If it is not, deleting it also orphans common.toggleOn and common.toggleOff in en.json and pt-BR.json, which nothing else uses.

Every workflow survived. Nine of the ten classes I was asked to hunt turned up something; "CI workflows that never ran" turned up nothing at all. Live run counts, read from the API, not from any document:

Workflow Runs Verdict
sonarcloud.yml 1,822 keep
test.yml 1,452 keep
dependabot-auto-merge.yml 894 keep
mutation.yml 696 keep
dependency-review.yml 694 keep
guards.yml 661 keep
react-doctor.yml 643 keep
arch-map.yml 501 keep
smoke-prod.yml 169 keep
visual.yml 96 keep, last 10 all green
android-release.yml 87 keep, dispatch only, releases do fail sometimes
perf.yml 82 keep, 8 of last 10 green
promote-prod.yml 5 keep, all 5 green, dispatch only

promote-prod.yml at five runs was the one that looked deletable. All five succeeded and it is a manual promotion tool, so a low count is what correct usage looks like.

Files with no inbound reference that are alive anyway. Each of these needed the "no importer does not mean dead" test:

File What I ruled out
packages/shared/src/types/__generated__/api.generated.ts Not an orphan: packages/shared/CONTRACT_DRIFT.md states "The generated file is never imported, it is a diff target only". It backs the required Contract Drift check. Deleting it breaks a merge gate.
.agents/skills/{orchestrate,pr-review,ticket}/SKILL.md Convention-discovered pointers for the Codex host, each explicitly "carries no behaviour, deliberately" so Claude and Codex cannot fork. Not an import target by design.
.claude/mcp.json.example A template meant to be copied. .gitignore ignores the .claude/mcp.json it produces.
apps/mobile/scripts/run-dev-client.js Human-invoked entry point. Zero references in the repo, in docs, or in the vault, which is why it made my candidate list. It launches expo start --dev-client --localhost with adb reverse, a genuinely different job from the wired run-android.js (expo run:android), so it is not a superseded twin. Kept.
apps/mobile/scripts/test-build-admob-env.js Required at android-release-apk.js:5. The name looks like a test; it is not.
apps/mobile/scripts/assert-production-admob-config.js Wired at android-release.yml:286.
sonar-project.properties Read by the SonarCloud scanner from the repo root by convention, never by path.
.claude/manifests/surfaces.json (409 KB) Generated, but its generator and its consumer both run: surface-manifest.mjs writes it, capture-surfaces.mjs reads it.
architecture.json, architecture.html Generated by the live arch-map.yml, and root CLAUDE.md tells agents to read architecture.json instead of exploring.
tools/__fixtures__/orca-linear-envelopes.json (3,358 lines) Kept deliberately by the rebuild ADR as the evidence behind the "never assume an external interface" rule.
The 23 aliased test-mocks/*.ts, all 7 .claude/agents/*.md, both .claude/workflows/*.mjs All cited by a vitest.config.ts alias, a skill body, or a rule file. Checked individually.
design/handoff/** (40 files) Design source archive, and a historical record. Not instructions anyone acts on.
.claude/pending-lessons.md A historical record by construction: a staging log of lessons DROPPED and GRADUATED, with dated reasoning. It names deleted tools (merge-sweep.sh, nudge-worker.mjs) inside entries explaining what those tools were. Exactly the "record, not instruction" case.
AGENTS.md:67 naming tools/check-ticket.mjs Same: it sits inside the "never assume an external interface" section, describing a measured past defect in a tool that no longer exists. The rebuild ADR requires that section survive byte-identical. Untouched.
tools/lib/orchestrator-config.mjs:82 naming tier:cheap A comment stating the machinery is gone. A record of a deletion, not a live reference.

Orphan sweep over product code. I scanned all 1,931 modules under apps/ and packages/ for files with no inbound import, then hand verified all 40 candidates. Thirty eight were conventional entry points (Expo Router paths, test-mocks aliases, npm script targets, vitest setup files, an LHCI puppeteerScript, Expo native module platform variants). Two were real: the export {} mocks deleted above. Plus mono-toggle, held back for your call.

Gates

Every gate this repo owns, run on the final tree:

$ node tools/test-tools.mjs
PASS every registered case module ran at least one assertion
ORBIT TOOLS GATE OK                                          exit 0

$ node .claude/hooks/test-hooks.mjs
PASS frontmatter: the scan actually read definitions
ORBIT HOOKS OK                                               exit 0

$ node tools/check-dashes.mjs --check-baseline                exit 0
$ node tools/check-copy.mjs --check                           exit 0
$ node tools/check-suppressions-ratchet.mjs
apps/web/eslint-suppressions.json:    734 on main -> 734 here (ok)
apps/mobile/eslint-suppressions.json: 733 on main -> 733 here (ok)

$ npm run type-check      Tasks: 3 successful, 3 total
$ npm run lint            Tasks: 3 successful, 3 total   0 errors (150 pre-existing warnings)
$ npm run build           Tasks: 1 successful, 1 total
$ npm run test            Tasks: 4 successful, 4 total
    @orbit/eslint-rules     2 files
    @orbit/shared         127 files
    @orbit/web            309 files   2,550 tests
    @orbit/mobile         247 files
                          685 test files, all passing

test-tools.mjs and test-hooks.mjs were also run before the deletions, both green, so the after state is a real comparison and not a first ever run.

Cross-Platform Parity will not fire: apps/mobile/test-mocks/ is outside the apps/mobile/(app|components|hooks|stores|lib)/ scope the job matches.

One gap worth knowing about

The folded in .gitignore commit ignores agent scratch by shape: .tmp-*, .tmp_*, .sess-*, .session-*, .orca-*. The untracked file that motivated it was named .agent-scratch-extract.mjs, which none of those five patterns match. The gate as written would not have caught its own trigger case. I did not add a pattern, because this PR only deletes. It is a one line fix whenever you want it.

Not merged. Yours to merge.

Generated with Claude Code

thomasluizon and others added 2 commits August 4, 2026 15:36
Seven session-transcript parsers accumulated at the repo root on
2026-08-04 (.orca-extract, .sess-now, .session-durable and four more),
and eleven of the same class in iqpay-api. They are throwaway scripts an
agent wrote while analysing a session, and tools/README.md already says a
throwaway belongs in the scratchpad and never in a repo.

That rule was prose, so it decayed. The tell is the line this replaces:
.tmp_session_text.txt was added by exact filename after an earlier
instance, which fixed one file and left the shape open.

Ignores the shape instead: .tmp-*, .tmp_*, .sess-*, .session-*, .orca-*.

Verified no tracked file is newly ignored: the count of tracked-but-ignored
paths is 5 both before and after, all pre-existing ORB-116 screenshot
artifacts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every deletion below is a file whose reader was removed by the harness rebuild
(#676) or a file no reader ever had. Each was grepped across all three Orbit
repos and the brain vault before it went.

Five baselines and snapshots whose reader no longer exists:

  tools/lockstep-declarations.json   read by tools/check-lockstep.mjs
  tools/context-budget.json          read by tools/check-context-budget.mjs
  tools/on-demand-budget.json        read by tools/check-context-budget.mjs
  tools/archaeology-baseline.json    read by tools/check-archaeology.mjs
  tools/required-gates.json          read by tools/check-required-gates.mjs
  .claude/linear-team-labels.json    read by the tier-labels guards job

None of those five tools is on disk. required-gates.json names its own missing
reader in its "note" field. Two of them had also drifted into nonsense:
context-budget.json claims CLAUDE.md is 10,504 bytes when it is 6,654, and
on-demand-budget.json claims orchestrate/SKILL.md is 53,533 bytes when it is
19,024. Both numbers survived only because nothing reads them.

skills-lock.json, whose entire content was {"version":1,"skills":{}}. The
calibration job that wrote it is gone.

Two mocks that are literally `export {}` and are absent from every alias map in
apps/mobile/vitest.config.ts:

  apps/mobile/test-mocks/shared-empty.ts
  apps/mobile/test-mocks/shared-types.ts

Five ORB-116 artifacts untracked, not deleted from disk. .gitignore:72 already
ignores .artifacts/, which capture-surfaces.mjs regenerates; these five were
committed once in #636 and have been both tracked and ignored ever since. The
ignore rule is right, so the tracking was the error.

Dead references in two files. guards.yml's header listed thirteen jobs when the
file defines five, naming context-budget, archaeology, frontmatter, harness,
lockstep, calibration and tier-labels, all deleted, plus three escape-hatch
labels with no job left to honour them. second-opinion/SKILL.md still described
an unattended run as a `--sleep` run; that flag no longer exists.

Also carries the unpushed .gitignore commit that ignores agent scratch by shape,
since it gates the same class of file this sweep found.

Kept, having tried to prove them dead and failed: mutation.yml (696 runs),
perf.yml (82), visual.yml (96), promote-prod.yml (5, all green, dispatch-only),
.claude/mcp.json.example (a template to copy), .agents/skills/* (Codex-side
pointers), api.generated.ts (a Contract Drift diff target, documented as never
imported), and mono-toggle.tsx on both platforms, which has no importer but is
the settings toggle the Figma handoff specifies.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
orbit-ui-mobile-web Ignored Ignored Aug 4, 2026 7:33pm

Request Review

thomasluizon and others added 2 commits August 4, 2026 16:29
…obile lint hook

MonoToggle was implemented on both platforms and wired to nothing. No file in
either app imports it. Its only appearances anywhere were three coverage
exclusion lists, which record that it was never tested because it was never
used, not that anything uses it. Thomas confirmed it is not the intended
settings toggle, so it goes with everything its deletion orphaned:

  apps/web/components/ui/mono-toggle.tsx
  apps/mobile/components/ui/mono-toggle.tsx
  its entry in apps/web/vitest.config.ts and apps/mobile/vitest.config.ts
  both entries in sonar.coverage.exclusions, plus the prose naming it
  common.toggleOn and common.toggleOff in en.json and pt-BR.json

Those two locale keys had no other consumer. They land in both files in the
same edit, as the parity rule requires. The Figma handoff still defines
MonoToggle, so the design source is unchanged; only the unused code goes.

.gitignore gains .agent-scratch-*. The commit that added the scratch patterns
covers .tmp-*, .tmp_*, .sess-*, .session-* and .orca-*, and the untracked file
that motivated it was .agent-scratch-extract.mjs, which matches none of them.
The gate did not cover its own trigger case.

lefthook.yml loses --fix from mobile-eslint, because that hook could not pass.
Measured: `expo lint` exits 0, `expo lint --fix` exits 2. `expo lint` ignores
its file arguments and walks the whole app, so --fix repaired all 718 suppressed
local/spacing-scale violations across 65 unstaged files, which orphaned those
same 718 suppressions and tripped eslint's stale-suppression error. A hook that
mass-edits files nobody staged is a hazard even when it exits 0. Pruning the
suppressions does not help: nothing is stale until --fix creates the staleness.
stage_fixed went with it, since nothing is fixed now.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Architecture map drift went red on PR #679 (run 30943557070). architecture.json
and architecture.html are generated and committed, and arch-map.yml regenerates
then fails on any diff, so deleting common.toggleOn and common.toggleOff had to
land in the map in the same PR.

Regenerated with the workflow's own command, node tools/arch-map.mjs. The diff
is exactly those two i18n keys and nothing else.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Aug 4, 2026

Copy link
Copy Markdown

@thomasluizon
thomasluizon merged commit fcd2e1c into main Aug 4, 2026
28 checks passed
@thomasluizon
thomasluizon deleted the chore/delete-stale-harness-artifacts branch August 4, 2026 19:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant