You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Split out from #296, which fixes the immediate data loss. This is the design question underneath it.
The problem
adf compile --write expands .ai/ into the vendor files. adf tidy folds the vendor files back into .ai/. They are exact inverses, and nothing records which one a repo has chosen.
#296 stops tidy from eating compiled output. It does not answer "which mode is this repo in?", and that question has other consequences.
And adf compile --target all --check reports all four stale, permanently:
[stale] CLAUDE.md — out of date with .ai/ source.
Run: charter adf compile --target claude --write
[stale] AGENTS.md — out of date with .ai/ source.
...
That remediation line is wrong for this repo. Running it would replace the deliberate pointers with full compiled content — changing the repo's mode, not fixing drift. --check has no concept of pointer mode; it assumes compiled mode unconditionally and calls any pointer stale.
This is the same root cause #296 reports as a "related symptom", not a separate defect: the reporter saw permanent staleness becausetidy had turned their files into pointers.
Why the documented path walks into it
README.md:39 tells every new user:
npx charter adf compile --target all --write
then hook install --pre-commit, then commit — at which point the hook runs tidy. The quickstart puts a fresh repo into the oscillating state. #296 stops that from corrupting .ai/, but the repo still ends up with --check permanently red and a remediation that would flip its mode.
Options
Record the mode in .charter/config.json — e.g. vendor: "compiled" | "pointer". tidy no-ops in compiled mode; compile --write warns in pointer mode; --check only checks compiled-mode repos, and in pointer mode verifies the pointer is intact instead. Explicit, greppable, survives hand-editing. Costs a config migration and a default for existing repos.
Make them explicit inverses, last writer wins — most honest about intent, largest change, and does not help the pre-commit hook running tidy unattended.
Recommendation recorded during the #296 triage: 2 now (shipped in #296), 1 later. This issue tracks 1.
Also worth fixing when this is picked up
charter adf sync --write is a natural thing to reach for when --check says stale, and it is not the fix — it writes .ai/.adf.lock from declared SYNC: entries and reports Wrote empty lock file (no SYNC entries declared) when there are none. That message is accurate but lands as a dead end for someone chasing a stale compile --check. Worth a pointer in the output toward what staleness actually means once mode is a concept.
Acceptance
A repo can state its vendor mode, or it is inferred consistently by every command that cares (compile --write, compile --check, tidy, the generated pre-commit hook, doctor).
compile --check does not report a deliberate pointer as stale.
No remediation line suggests a command that would silently change the repo's mode.
Split out from #296, which fixes the immediate data loss. This is the design question underneath it.
The problem
adf compile --writeexpands.ai/into the vendor files.adf tidyfolds the vendor files back into.ai/. They are exact inverses, and nothing records which one a repo has chosen.#296 stops
tidyfrom eating compiled output. It does not answer "which mode is this repo in?", and that question has other consequences.Evidence it is not hypothetical: this repo
Charter's own vendor files are thin pointers:
And
adf compile --target all --checkreports all four stale, permanently:That remediation line is wrong for this repo. Running it would replace the deliberate pointers with full compiled content — changing the repo's mode, not fixing drift.
--checkhas no concept of pointer mode; it assumes compiled mode unconditionally and calls any pointer stale.This is the same root cause #296 reports as a "related symptom", not a separate defect: the reporter saw permanent staleness because
tidyhad turned their files into pointers.Why the documented path walks into it
README.md:39tells every new user:then
hook install --pre-commit, then commit — at which point the hook runstidy. The quickstart puts a fresh repo into the oscillating state. #296 stops that from corrupting.ai/, but the repo still ends up with--checkpermanently red and a remediation that would flip its mode.Options
.charter/config.json— e.g.vendor: "compiled" | "pointer".tidyno-ops in compiled mode;compile --writewarns in pointer mode;--checkonly checks compiled-mode repos, and in pointer mode verifies the pointer is intact instead. Explicit, greppable, survives hand-editing. Costs a config migration and a default for existing repos..githooks/pre-commit:16has done in the field. But a repo can sit mixed indefinitely, and stripping the banner silently flips a file's meaning.tidyunattended.Recommendation recorded during the #296 triage: 2 now (shipped in #296), 1 later. This issue tracks 1.
Also worth fixing when this is picked up
charter adf sync --writeis a natural thing to reach for when--checksays stale, and it is not the fix — it writes.ai/.adf.lockfrom declaredSYNC:entries and reportsWrote empty lock file (no SYNC entries declared)when there are none. That message is accurate but lands as a dead end for someone chasing a stalecompile --check. Worth a pointer in the output toward what staleness actually means once mode is a concept.Acceptance
compile --write,compile --check,tidy, the generated pre-commit hook,doctor).compile --checkdoes not report a deliberate pointer as stale.