ONB — TFW-60 / Phase AA: Portable Delivery¶
Date: 2026-08-27 Author: Claude Code (Executor),
actor: saubakirov,via: claudeStatus: 🟠 ONB — Awaiting answers Parent HL: HL-TFW-60 Phase HL: HL Phase AA TS: TS Phase AA Origin read: FIELD-REPORT F1–F10 and §6 Predecessor RF read: Phase A RF Measured at: working tree866c38d, 2026-08-27. Two files are dirty from unrelated tasks (TFW-55research/iterations.yaml, TFW-54HL-TFW-54__…) — see Risk 6.
1. Understanding¶
Phase A shipped a task model that works in this repository and cannot be handed to another one.
Four things the release requires are outside the payload /tfw-update copies: gen_index.py,
migrate_board.py, a team/ explanation, and a migration guide that never existed. The first
external consumer completed its update anyway — by hand-carrying files and reconstructing an
order the release states once, in a code fence, inside a CHANGELOG.
Phase AA closes that gap and nothing else. The model is untouched: no carrier schema, no event
grammar, no lifecycle value, no identifier rule. The work is a git mv and everything that names
its result, a migration guide written for a project that is not this one, five defects the external
run found in the two scripts, a post-update self-check that reports and exits, one adapter route
that has been broken for two releases, one out-of-theme session-naming fix, and a 2.0.0-dirty.2
release surface that describes what shipped.
The phase passes or fails on one thing: at least one project other than this one completes the
update with zero hand-carried files and zero edits inside .tfw/. Every Phase A review round ran
here, which is why none of this was found. Question 1 is therefore the question that decides whether
this phase can be executed at all.
2. Entry Points¶
The move and its dependents¶
| Path | Why it matters |
|---|---|
| gen_index.py | 41,732 B. --root default parents[2] at L871. TASK_DIR L52, LEGACY_ID L49, parse_identifier L92, iter_task_dirs L146, read_status L186 (F5 message at L203), collect L640 (F4 drop at L171–172), Backlog render L812 |
| migrate_board.py | 29,714 B. BOARD_HEADING L49 (F3), read_board L546 (F8), parents[2] L605, empty-board refusal L637, "backlog idea, never started" L444 (F4), sys.path.insert(parent) L37 |
| test_gen_index.py · test_migrate_board.py | 131 passed, 1 skipped — matches the field report exactly |
| gen_docs.py | import gen_index at L18 — a bare same-directory import. Root derivation at L190 |
| test_integration.py | L174 globs docs/scripts/*.py; L309 lists shipped-text roots including docs/scripts |
| docs/mkdocs.yml | gen-files runs scripts/gen_docs.py relative to docs/. Unaffected by the move; the import at L18 is not |
Normative references and the release surface¶
.tfw/conventions.md:332 · .tfw/glossary.md:309 · .tfw/project_config.yaml:132,133,139 ·
.tfw/workflows/init.md:69,233 · README.md:257 · .tfw/CHANGELOG.md:75,79,91,120,131,132 ·
KNOWLEDGE.md:22 (see Q5) · workspace/00-INDEX.md:4,14,123 (generated).
The eleven provenance comments — confirmed¶
git grep -l "Written by docs/scripts/migrate_board.py" returns 13 files: migrate_board.py
itself, the Phase AA TS, and exactly eleven status.md files. The TS's count is correct and
their bytes stay.
Baseline measurements taken before any edit¶
| Measurement | Value |
|---|---|
pytest docs/scripts/ -q |
220 passed, 1 skipped, 305 s |
pytest test_gen_index.py test_migrate_board.py -q |
131 passed, 1 skipped, 4.9 s |
update.md |
835 words (design ceiling 1200) |
init.md · plan.md |
1,821 · 1,501 words — both already over the ceiling |
| Adapter copies vs sources | all 22 byte-identical. Nothing is out of sync going in |
| CI | .github/workflows/docs.yml runs mkdocs build only. No CI change needed — no pipeline runs pytest |
The AC-13 fixture, located¶
D:\projects\KZ-IT-telegram-list is reachable, clean, at 2.0.0-dirty. Its pre-update commit
c919640 (parent of 97dd429) is a complete external fixture at TFW 1.3.0:
- board at
tasks/README.mdunder## Board, with a separate## Backlog— exactly F3; - four task directories, mixed grammar:
TFW-01_…,TFW-02_…(single_),TFW-3__…,TFW-4__…— exactly F4; task_containers: [tasks], one container — not this repository's two;- no TFW version tags at all (
git tag -l→data-2026-08-27only), which relocates AC-10 — see Recommendation 8.
3. Questions (blocking — cannot proceed without answers)¶
| # | Question | Answer |
|---|---|---|
| 1 | AC-13 — which project is the external fixture, and may I create it? The only external consumer has already migrated, so a 2.0.0-dirty → 2.0.0-dirty.2 update there exercises payload delivery but can never exercise AC-2's guide (it does not cross a major), AC-3's board locator, AC-4's classification or AC-8's revision default. Options: (a) clone KZ-IT-telegram-list at c919640 into the scratch directory and run the full 1.3.0 → 2.0.0-dirty.2 update there — real corpus, real board location, real mixed grammar, reproducible, and not this repository; (b) name another real pre-2.0.0 project; (c) run against the live consumer only and mark the migration half of AC-13 DEFERRED. (a) needs your authorization because it writes outside this repository. My recommendation is (a) plus a second, lighter run against the live consumer — (a) covers migration, the live run covers the payload path a real operator will actually take |
(a), with a distinction the TS failed to make. Clone to scratch and build against it. Never touch the live consumer — it is the owner's project, and a second agent writing into it is the F14 / TD-144 defect this whole task exists to end. The distinction: a development fixture is not acceptance evidence. You need the first to build AC-2, AC-3, AC-4 and AC-8 at all; the owner's real runs are the second. AC-13 as written conflates them and is being amended. Your clone at c919640 closes the fixture half. The evidence half is closed by the owner updating two real projects, and you report it unmet and hand it back. If your RF ever says the external check passed on your own clone, that is the fifth form of the DoF pattern and review must reject it. |
| 2 | Where does the AC-13 field report live? Its predecessor sits at task root as FIELD-REPORT__TFW-60__first_external_update.md. Options: a second root-level FIELD-REPORT__TFW-60__second_external_update.md; or phase-aa/evidence/ as an evidence attachment indexed in the EV file. The first matches precedent and is visible to Phases B and C; the second keeps phase evidence in one place. Which? |
Both, split by what they are. Your clone run is evidence: phase-aa/evidence/, indexed in the EV file. The owner's real external run is advisory input the whole task reads, so it goes to task root as FIELD-REPORT__TFW-60__second_external_update.md, matching its predecessor and visible to Phases B and C. You author the first and not the second. |
| 3 | AC-14 — may the executor create the v2.0.0-dirty.2 tag? §15 Role Lock assigns VERSION and CHANGELOG.md to release.md / Coordinator; this TS assigns them to me under "Release surface", which I read as authorized. The tag is different, and AC-13 needs a source the fixture can be pointed at. Options: (a) I write VERSION + CHANGELOG, commit, create the local annotated tag, run AC-13 against it — the fixture then exercises the real "clone a tag" path; (b) I write VERSION + CHANGELOG and commit, AC-13 runs against that commit SHA, and /tfw-release cuts the tag after approval — no executor tag, at the cost of AC-13 not testing the tag path. No push either way, per Commit Attribution |
(b). conventions.md §15 assigns release.md to the coordinator and a tag is a release act; more to the point, a tag on unreviewed work asserts releasability, which is the reviewer's finding to make, not yours. You write VERSION and CHANGELOG.md — the TS authorizes those and I confirm it — commit, and point the fixture at that commit SHA. On the cost you name: git clone plus git checkout <sha> exercises the same mechanics as a tag; a tag adds a name, not a path. And the real tag path does get tested — I cut v2.0.0-dirty.2 after review, and the owner's two updates run against it. The people who matter test it, just not inside your pass. |
| 4 | AC-11 census growth — two adapter source files the TS does not name. /tfw-research routes to the non-existent .tfw/workflows/research.md in three adapter sources, not one: claude-code/CLAUDE.md.template:31 (named in TS §4), claude-code/README.md:43, antigravity/README.md:22,64. AC-11 says "every path in every adapter source resolves; a test fails if one does not", so a test satisfying AC-11 fails on all three. Approve adding both files to Modify, or bound AC-11 to the template and let the test allow the two READMEs (in which case AC-11's own gate cannot be written as stated)? |
Add both to Modify. You are right that bounding AC-11 to the template makes its own gate unwritable, and an AC whose gate cannot be written is not an AC. claude-code/README.md and antigravity/README.md join the census; Modify moves to roughly 25 against a limit of 30. This is the return-to-coordinator rule working as intended — a group appeared, you raised it before acting, nothing was absorbed silently. |
| 5 | KNOWLEDGE.md:22 is a normative reference to docs/scripts/gen_index.py. AC-1 requires every normative reference to name the payload path, and its gate says the grep "returns only historical trace artifacts and the eleven provenance comments" — KNOWLEDGE.md is neither. TS §9 says KNOWLEDGE.md is untouched. Options: (a) I change that one path (contradicts §9 as written); (b) /tfw-docs changes it after approval, and AC-1's gate is amended now to name KNOWLEDGE.md as a known exception so the RF does not report a green gate that is red; (c) amend AC-1's gate to exclude it permanently. Silence is the one option I will not take: an unexplained grep hit is the shape of DoF's "a check reported as passing that never ran" |
(b). KNOWLEDGE.md belongs to /tfw-docs under the D37 ownership split and you do not write it. AC-1's gate is amended now to name it as a known exception, and the reference is added to the RF §6 observations so /tfw-docs closes it after approval. Your closing line is the right instinct and I am recording it as the reason: an unexplained grep hit is exactly the shape of a check reported as passing that never ran. |
| 6 | AC-9 — where does the self-check live? Field-report rec 9 proposed gen_index.py --doctor. AC-9 says only "one command". Options: (a) a --doctor flag on gen_index.py — no new file, and it inherits the report-and-exit character --validate already has, but it puts payload/team//config checking inside the index generator; (b) a new .tfw/scripts/doctor.py plus test_doctor.py — Create goes 7 → 9 (limit 15), a cleaner separation, and one more file for a receiving project to know about. My recommendation is (a): AC-9's "it is named in the migration guide as the last step" is easier to satisfy with a command the project already runs |
(a) — --doctor on gen_index.py. Your reasoning holds, and there is a second reason: the file already carries --validate, which validates task state rather than the index, so it is not a pure generator today and --doctor does not make it one. Fewer commands for a receiving project to learn wins. Non-negotiable rider from your own inconsistency 6: the output must state that it does not answer index freshness, or the next operator reads one flag's silence as the other's answer.⚠ SUPERSEDED at TS R3 — do not implement this answer. The owner challenged the phase's additions and this one did not survive. Your inconsistency 6 described the trap and I accepted the trap instead of removing it: project_config.yaml already needs five lines of comment to keep --check and --validate apart, and I approved a third synonym. When prose is required to distinguish your own names, the names are wrong. The three collapse into --check index / --check tasks / --check project, and the comment is deleted rather than rewritten. TS §5 AC-9 carries it. |
| 7 | AC-4 — confirm "reported", not "matched". AC-4 allows the single-underscore legacy form to be "either matched or reported". Matching it means editing LEGACY_ID/parse_identifier, which is an identifier rule, and TS §7 DoF forbids "any edit to … the identifier rules". So only reported is available. Confirm, because if you meant matched, this is a materially larger and DoF-conflicting change |
Confirmed — reported, never matched. You read DoF correctly; widening LEGACY_ID is an identifier rule change and is forbidden here. One addition, so the consequence is not left as a dead end: the migration guide tells the operator that a directory reported as unresolved may be renamed by hand to the recognized grammar if they want it picked up. That keeps it a human act with a trace, and it is the same shape as the UNDECLARED ruling — the tool never normalizes, an accountable person may resolve. |
| 8 | AC-8 — what happens when there is no committed board to read? Defaulting read_board() to a committed revision needs a defined behaviour when the project is not a Git repository, or README.md (or --board) does not exist at HEAD. Options: (a) refuse, naming the working-tree opt-in — consistent with the empty-board refusal, and it never silently reads a stale or a live file; (b) fall back to the working tree with a printed notice — friendlier, and it reintroduces exactly the silent live read AC-8 exists to remove. My recommendation is (a), with the printed revision that AC-8's third bullet already requires |
(a) — refuse, naming the working-tree opt-in. Consistent with the empty-board refusal you are preserving, and (b) reintroduces the silent live read that AC-8 exists to remove. A printed notice is the thing nobody reads. The refusal names the opt-in flag and prints the revision it tried, per AC-8's third bullet. |
⚠ Two coordinator answers below were superseded on 2026-08-27 by TS revision 3 — Q6 and inconsistency #1. The originals stay visible and are marked in place; a superseded instruction is corrected by appending, never by overwriting, which is the rule the journal and §12 already follow. The TS is the authority. Where this file and the TS disagree, the TS is right.
3a. Coordinator rulings on §4, §5 and §6¶
Answered here rather than left silent, because several are decisions and not suggestions.
Recommendations — all eight approved. Two are more than approvals:
- Rec 2 is a finding, not a tidy-up.
build.*sits under "Project sections (preserve)" inupdate.md, so a receiving project keeps abuild.verifynaming a path that no longer exists. That is a second instance of F1's own class, arriving through the update path this phase is fixing. The migration guide must namebuild.*as something the operator edits by hand. Had you not raised it, it would have shipped again. - Rec 8 is a correctness catch. The consumer has no TFW tags at all; the pristine-tag diff ran against
the source tree.
update.mdmust say whose tag, or an operator looks for a tag their project never had and concludes the technique does not apply.
Risks — acknowledged, and Risk 4 changes how AC-1 is verified.
- Risk 4 is the sharpest thing in this onboarding.
parents[2]resolving correctly by coincidence at.tfw/scripts/means a source-only move passes every test here while leaving F1's aggravating detail fully intact — and AC-1's stated gate does not catch it, because the default is relative to the script file rather than the cwd. Your fixture — the tools copied to a different depth inside a project — is the observable test, and AC-1's gate is amended to require it. - Risk 5, census. Your enumeration is authoritative; TS §4's
Modify — 26was my estimate and the table under-listed. The RF carries the counted number, not mine. With Q4's two additions andKNOWLEDGE.mdexcluded by Q5, expect roughly 25 against a limit of 30. - Risk 6, dirty tree. Your stance is correct and is now a rule for this phase: pin a commit that excludes the other tasks' artifacts and say so in the EV file. Do not commit another task's work to make your own measurement clean.
- Risks 1, 3 and 7 approved as you propose — one code path for AC-3 and AC-8, a skipped
.upstreamsegment with the resolved root printed every run, andworkspace/00-INDEX.mdregenerated and counted as derived output rather than a modified file.
Inconsistencies — you are right on all six. Two are my errors:
- #1 —
team_README.mdviolatesconventions.md§10.4. Useteam_readme.md. My TS was wrong; the TS is corrected rather than left for you to deviate from.⚠ SUPERSEDED at TS R3 — the file is withdrawn, not renamed. Renaming was the small answer to a correct catch. The owner asked the larger question and it does not survive:
templates/research/,templates/evidence/andtemplates/review/had already settled that a template producing into a directory lives in a directory — so the right name wastemplates/team/README.md, and the right answer was that no such template is needed at all. AC-7 createsteam/together with its first profile, so an unexplained directory never appears, and the content duplicatedconventions.mdat three separate points. Create nothing here. Three existing templates also move into that shape:team_profile→team/profile,journal_event→journal/event,topic_file→knowledge/topic. - #2 — the HL diagram is loose, the TS is right.
team_profile.mdalready exists. A Phase HL is derivation-only and carries no contract, so nothing is amended; recorded so the reviewer does not read the diagram as a second requirement. - #4 and #5 — naming the offending key means deriving it from the raw front-matter at the marked line,
and the template's example is invalid on
goal,valueandauthorityas well astitle. Both are in scope; AC-5 means all of them. - #3 and #6 acknowledged as you state them.
#6 updated at TS R3. You were right that the trap exists; naming it was not enough. The flags merge, so there is no
--doctorsilence for an operator to misread and no comment to maintain.
4. Recommendations (suggestions, not blocking)¶
-
Keep
update.mdunder the 1200-word ceiling by routing, not by prose. It is at 835 words and AC-2, AC-6, AC-7, AC-9 and AC-10 all add to it. Written out in full that is roughly +400–600 words and the file lands at 1250–1450, over the §11 design rule. I intend to put the decision and the route inupdate.md(one or two lines each) and the reasoning, the ordering constraint and the worked commands in.tfw/migrations/2.0.0.md. This also serves AC-2's "the ordering constraint appears where a reader is about to violate it". If you want the detail inline instead, say so — it is a convention overrun and it should be your call, not mine. -
build.lintandbuild.testrunpytest docs/scripts/ -q(project_config.yaml:132–133). After the move that command no longer runs the two suites this release cares about. I will point them at both directories. The delivery consequence is bigger than the edit:update.mdlistsbuild.*under "Project sections (preserve)", so a receiving project keeps its own stale command and itsbuild.verifykeeps namingdocs/scripts/gen_index.py. The migration guide must namebuild.*as something the operator updates by hand. This is a second instance of F1's class and it would otherwise ship again. -
test_no_board_shaped_regex_survives_in_the_generators(test_integration.py:174) globsdocs/scripts/*.py. After the movegen_index.pyleaves that directory and the test's coverage silently shrinks while it keeps passing — the exact shape of DoF's "a check reported as passing that never ran". I will make it scan both directories and assert that it found the files it expects to find, so an empty glob fails instead of passing. -
Add a sibling
iter_unmatched_task_dirs()rather than changeiter_task_dirs()'s signature. F4's mechanism isgen_index.py:171–172: a directoryparse_identifierrejects iscontinued, so it never reachesunresolved— that is why the consumer saw 2 directories where 4 exist.iter_task_dirsis called bygen_docs.py:348,migrate_board.pyand the tests; returning a tuple would break all three. An additive sibling keeps the working callers working. -
AC-11's path checker needs a declared allowlist. A naive resolver over adapter copies reports 16 failures that are all correct paths:
~/.tfw/bindings.yamlis per-machine and deliberately outside the tree, and.tfw/.upstream/.tfw/CHANGELOG.mdis created at runtime byupdate.mdStep 0. The allowlist must be short, named and commented, or the test gets disabled the first time it cries wolf. -
gen_docs.py:18is a bareimport gen_indexthat works only because the two files share a directory. After the move it needs an explicitsys.pathinsert of<root>/.tfw/scripts, bootstrapped fromgen_docs.py's own root derivation at L190.mkdocsruns it through thegen-filesplugin withdocs/as the config root, so this path must be absolute, not relative to the cwd.mkdocs buildis a gate for exactly this reason. -
.tfw/scripts/README.mdshould state the root-resolution rule, not just the commands. AC-1's "the tools work wherever a project places them" is only true to a project that knows it is true. One sentence — the tools find the project root by walking upward for.tfw/, so you may put them anywhere — is what converts the code change into a delivered capability. -
AC-10's "pristine previous tag" lives in the source, not the receiver. The consumer has no TFW version tags at all; the field report's
git show v1.3.0:.tfw/<f>ran against the source tree, which does havev1.3.0andv2.0.0-dirty.update.mdmust say whose tag, or an operator will look for a tag their own project never had and conclude the technique does not apply to them.
5. Risks Found (edge cases, potential issues not in TS)¶
-
AC-3 and AC-8 interact and the TS treats them separately. Once
--boardcan name a path and the default input is a committed revision, the board must be read asgit show REV:<board-path>. Reading--boardfrom the working tree while claiming a revision would produce a run whose log names a revision it did not read — a false provenance statement, which is worse than either defect alone. I will implement them as one code path. -
AC-2's routing cannot fire on the live consumer. "Route to the guide when the update crosses a major" —
2.0.0-dirty → 2.0.0-dirty.2does not cross a major. So a run against the already migrated consumer exercises the payload and skips the guide entirely. This is the mechanical reason Question 1 needs a pre-2.0.0 fixture, not a preference for thoroughness. -
The marker search can resolve the wrong root. Walking upward for
.tfw/finds.tfw/.upstream/as a project root for any tool run from inside the staging directory thatupdate.mdStep 0 creates. Arguably correct, and it means an operator can silently generate an index for the upstream clone instead of their own project. I intend to skip a candidate whose path contains a.upstreamsegment and to print the resolved root on every run, so a wrong answer is visible rather than inferred. -
parents[2]coincidentally still resolves correctly at.tfw/scripts/. From.tfw/scripts/gen_index.py,parents[2]is the project root — so a source-only move would pass every test in this repository while leaving F1's aggravating detail fully intact. AC-1's stated gate ("run both tools from a checkout placed at a different depth") does not catch it either, because the default is relative to the script file, not the cwd. The observable test is a copy of the tools at a different depth inside a project — e.g.tools/tfw/gen_index.py— and that is the fixture I will use. -
Census reconciliation. TS §4 declares Modify — 26; the paths its table actually lists count to 23 by my enumeration (4 normative + update + plan + status template + adapter template + 3 tooling + 3 release + 9 adapter copies). My census adds 2 (Question 4) and possibly
KNOWLEDGE.md(Question 5), reaching 25–26. Nothing crosses a limit (30 modified, 15 new). I am raising it rather than resolving it because DoF requires it and because the RF's accounting has to match a number the TS can be diffed against. -
The working tree is dirty with two unrelated artifacts — TFW-55's
research/iterations.yamland an untracked TFW-54 HL. TS §6 requires evidence measured at a pinned commit. Either those land under their own task first, or my pinned commit deliberately excludes them and the EV file says so. I will not commit another task's artifacts to make my own measurement clean. -
workspace/00-INDEX.mdwill change without being in the census. It is generated and carries three references todocs/scripts/gen_index.py(L4, L14, L123). Regenerating it is correct and costs nothing; leaving it stale leaves three wrong paths in a file the README routes readers to. I will regenerate it and count it as a derived output, not a modified file — flagging the choice because a reviewer will otherwise find an uncounted diff.
6. Inconsistencies with Code (spec vs reality)¶
-
.tfw/templates/team_README.mdviolates conventions §10.4. TS §4 Create names that filename; §10.4 says "Markdown templates in.tfw/templates/also followlower_snake_case" and reserves uppercase for project-root documents and.tfw/framework docs — a template is neither.team_readme.mdcomplies; every existing sibling (team_profile.md,topic_file.md,journal_event.md) does too. I will useteam_readme.mdunless you say otherwise, and record the deviation from the TS in the RF. -
HL and TS name different new files for AC-7. The Phase HL's AFTER diagram says
templates/team_profile.md + a step that creates the acting profile;team_profile.mdalready exists and needs no creation. The TS's Create list saysteam_README.md, which is theteam/directory README. Reading both with the field report's rec 7 ("aREADMEtemplate inside.tfw/"), the TS is right and the HL diagram is loose. Recording it so the reviewer does not read the HL as a second requirement. -
F4 is one classification, not two. AC-4 requires "the manifest and the index agree", which reads as two fixes. They already share a source:
migrate_board.reconcile()assigns"board-only, backlog"(L381) and the reason string"backlog idea, never started"(L444), andgen_index.collect()rendersBacklogfrom that same snapshot class (L704). Fixing the classification fixes both consumers. Good news, recorded so the RF's two ticks are not read as two independent verifications of one change. -
F5's "name the offending key" is not available from the exception. The message comes from
read_status(L203) andread_phase_status(L308) asexc.__class__.__name__.yaml.MarkedYAMLErrorcarriesproblem_mark/context_mark— a line and column, not a key. So naming the key requires deriving it from the raw front-matter text at that line. Feasible and worth it, and materially more than a message change. AC-5's gate ("feed five files whose titles contain a colon-space; each error names its key") is what I will build against. -
The
status.mdtemplate's example is invalid under its own advice in more than one line. F5 namestitle: short task name.goal:,value:andauthority:model the same unquoted form, andgoal: why this task exists, one lineis exactly the shape that breaks — a plain scalar with punctuation. AC-5's "the template's example quotes its values" is therefore all of them, not one. -
--validateand--doctorhave no overlap problem, but--checkdoes.project_config.yamlcarries a deliberate comment explaining whybuild.verifyis--validateand not--check(--checkasks whether the shared index is current, which would make every task-local transition fail a gate). If AC-9 becomes--doctor(Question 6a), its output must state that it does not check index freshness, or the next operator will read one flag's silence as the other's answer. AC-9's "its output names what it did not check" covers this; naming the specific trap here so it is not left to judgement.
7. Knowledge Citations¶
Coordinator's citations: master HL §7.2, 29 items. All 29 read. Phase AA is a delivery phase, so a large share are correctly N/A — they governed Phase A's design of the model, and this phase changes no part of the model. Each N/A states why rather than deferring to the group.
| # | HL §7.2 ref | Read? | Applied / N/A | Notes |
|---|---|---|---|---|
| 1 | PV 0 — README.md opening · § How It Works |
✅ | Applied | Bounded resumability is what AC-2's guide and AC-9's self-check deliver to a project that has no session history here. README.md:257 is also a census hit |
| 2 | PV 0 — .tfw/README.md NS1, NS2 (principles 3, 5) |
✅ | Applied | Authorized continuation is exactly what a receiving project cannot do today: it is told to run a file it does not have. AC-1 is this clause made true off-site |
| 3 | PV 1 — Structural Enforcement | ✅ | Applied | Drives Recommendation 3 and Risk 4. A gate whose glob has moved out from under it, or a depth check parents[2] still satisfies by accident, is prose wearing a test's clothes |
| 4 | PV 1 — one authoritative owner per truth type | ✅ | Applied | The load-bearing constraint on AC-9: the self-check reports and exits. The moment it writes it becomes a second authority over task state |
| 5 | PV 1 — Portability · Success Criteria | ✅ | Applied | The whole phase. Provider-independent durable context is not portable if the payload cannot carry its own tooling. No package manager, no installer — ordinary files, per HL's exclusions |
| 6 | PV 2 — philosophy.md F4 (structural gates beat state tables) |
✅ | Applied | AC-11's path test and AC-9's self-check are structural. The field report's own finding was that the best available signal was two framework tests a consumer was never told to run |
| 7 | PV 2 — F11 (TFW Markdown is the knowledge graph; avoid extra entities) | ✅ | Applied | Argues for Question 6 option (a): a flag on a tool the project already runs, over a fourth script it must learn about. Also argues against a migrations/ index file — one guide per major, routed to, no registry |
| 8 | PV 2 — F27 (observable file-by-file progress is stakeholder value) | ✅ | Applied | Shapes AC-9's output: per-check lines a person can act on, plus an explicit list of what it did not check |
| 9 | PV 2 — F34 (a vague request must lead through discovery to a usable result) | ✅ | Applied | Question 1 is this clause. "An external project" is not usable until a specific fixture exists and is authorized |
| 10 | PV 2 — F38 (coordinator attention is finite) | ✅ | Applied | Why the eight questions are batched into one file with options and a recommendation each, rather than arriving as eight turns |
| 11 | PV 3 — KNOWLEDGE.md D31, D50 (filesystem state and locality) |
✅ | Applied | Phase A's foundation, unchanged here. Cited because Question 5 concerns KNOWLEDGE.md:22, which is where D31/D50's mechanism is indexed — including the path this phase moves |
| 12 | PV 3 — D37 (exclusive knowledge write territories) | ✅ | N/A | Phase C's concern. Nothing here writes knowledge/ or touches /tfw-docs versus /tfw-knowledge ownership. It is why Question 5 offers option (b) rather than assuming I may edit KNOWLEDGE.md |
| 13 | PV 3 — D43 (knowledge citation cascade) | ✅ | Applied | This section is the cascade's executor link. Recorded per row, with N/A justified per row |
| 14 | PV 3 — D55, D59 (commit attribution; capability claims keep boundaries apart) | ✅ | Applied | Commits use [claude-code/TFW-60/phase-aa/executor]; no push without approval. D59 is Question 3: writing VERSION is authorized by the TS, cutting a tag is a release capability and I am not assuming it |
| 15 | PV 3 — D65 (reverting a result never reverts its trace) | ✅ | Applied | The 82 never-modify artifacts and the eleven provenance comments. Rewriting a comment about a past act at a path that was correct then would make the record say something that did not happen |
| 16 | PV 4 — conventions.md §§3–5 |
✅ | Applied | §4's identifier rules are what collapse AC-4 to reported (Question 7). §10.4's naming rule is Inconsistency 1. §11's word ceiling is Recommendation 1 |
| 17 | PV 4 — §13, §14 (trace discipline; whole-tree restore failure) | ✅ | Applied | The move is git mv, not copy-and-delete — a script whose history stops at Phase AA loses four rounds of reasoning. No trace deletion anywhere in this phase |
| 18 | PV 5 — convention.md F22 (root board update is a process artifact) |
✅ | N/A | Settled by Phase A: the live board is retired and its bytes are in BOARD-SNAPSHOT.md. Phase AA only makes the board's location an input for projects that still have one (AC-3) |
| 19 | PV 6 — process.md F7, F30 (cross-session context is lost; capture without enforcement changes nothing) |
✅ | Applied | F30 is the field report's own thesis restated: "the file copying took minutes; the rest of the session was reconstructing what to do and in what order." AC-2 is the enforcement half — a guide routed to from the step that needs it, not prose in a CHANGELOG |
| 20 | PV 7 — risk.md F1 (two sessions share one Git index; verbal warning 0/1) |
✅ | Applied | Directly operational: the AC-13 fixture is a separate clone with its own index (Question 1a), never a second working tree over this one |
| 21 | PV 7 — constraint.md F1, F3 (shared personal state is unsafe; templates generate filler) |
✅ | Applied | F1 bounds AC-7: team_readme.md explains the directory and the binding's location outside the tree, and ships no participant. F3 is why .tfw/scripts/README.md gets Recommendation 7's one load-bearing sentence instead of a generated wall |
| 22 | RES 1 — YAML 1.2.2 | ✅ | Applied | AC-5's root cause is a spec fact: a colon followed by a space ends a plain scalar. Both the quoted example and the key-naming validator derive from it |
| 23 | RES 1 — RFC 8259 | ✅ | N/A | JSONL was not the chosen journal carrier; Phase AA changes no carrier |
| 24 | RES 1 — Git · git-rev-parse · git-add | ✅ | Applied | AC-8's committed-revision default is git show REV:<path>; Question 8 is precisely the "is this even a repository" preflight this citation warns about |
| 25 | RES 1 — Google Drive troubleshooting | ✅ | N/A | Transport mode is TFW-61. AC-8's quiescence rule is prose in the guide, not a sync assumption |
| 26 | RES 1 — OneDrive sync troubleshooting | ✅ | N/A | Same boundary as 25 |
| 27 | RES 1 — Dropbox conflicted copies | ✅ | N/A | Same boundary as 25 |
| 28 | RES 1 — gsd-pi · BMAD · Hermes · Spec Kit · OpenSpec | ✅ | Applied, as counter-evidence | Every one of them ships its tooling inside the artifact it distributes. That comparison is the strongest available argument for .tfw/scripts/ over the sync-table alternative rec 1 offered as a fallback |
| 29 | RES 2 — git-interpret-trailers · git-log · git-merge-base | ✅ | N/A | Phase A's L3 landing-completion derivation. Untouched here |
New items the coordinator did not cite¶
| # | Source | Item | Why it belongs |
|---|---|---|---|
| N1 | .tfw/conventions.md §10.4 |
YAML and Markdown template naming is lower_snake_case; uppercase is reserved for project-root and .tfw/ framework docs |
Decides Inconsistency 1. The TS's team_README.md does not comply and no §7.2 row covers naming |
| N2 | .tfw/conventions.md §11 Design Rules |
Workflow instructions ≤ 1200 words; enforcement-critical values inline | Governs Recommendation 1 — five ACs land in one 835-word file. Not in §7.2, and it is the binding constraint on how AC-2, AC-6, AC-7, AC-9 and AC-10 are written |
| N3 | .tfw/conventions.md §10.3 File Classification |
build.* and task_containers are project sections that an update preserves |
Recommendation 2's delivery consequence: a preserved section keeps a stale path forever, so the guide must name it by hand. This is F1's class recurring in the config, and no §7.2 row reaches it |
| N4 | .tfw/templates/journal_event.md |
Closed kind vocabulary; the timestamp is read from the clock |
The F9 ruling's basis — the vocabulary stays closed and the canon states some artifacts have no event. Cited because AC-14's fourth bullet asks me to write that rule into the canon |
ONB — TFW-60 / Phase AA: Portable Delivery | 2026-08-27