@techierathore/techieflow 1.0.3 → 1.1.0

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.
Files changed (150) hide show
  1. package/.claude/commands/TechieFlow/agents/analyst.md +5 -8
  2. package/.claude/commands/TechieFlow/agents/architect.md +1 -10
  3. package/.claude/commands/TechieFlow/agents/flow-master.md +1 -0
  4. package/.claude/commands/TechieFlow/agents/verifier.md +1 -0
  5. package/.claude/commands/TechieFlow/tasks/_owner-language.md +27 -0
  6. package/.claude/commands/TechieFlow/tasks/_smoke-test-policy.md +1 -1
  7. package/.claude/commands/TechieFlow/tasks/_status-update-gate.md +4 -3
  8. package/.claude/commands/TechieFlow/tasks/amend-docs.md +6 -5
  9. package/.claude/commands/TechieFlow/tasks/build-phase.md +1 -1
  10. package/.claude/commands/TechieFlow/tasks/create-deep-research-prompt.md +4 -0
  11. package/.claude/commands/TechieFlow/tasks/create-doc.md +4 -0
  12. package/.claude/commands/TechieFlow/tasks/create-project-brief.md +22 -0
  13. package/.claude/commands/TechieFlow/tasks/day1-brownfield.md +3 -3
  14. package/.claude/commands/TechieFlow/tasks/day1-greenfield.md +3 -3
  15. package/.claude/commands/TechieFlow/tasks/facilitate-brainstorming-session.md +4 -0
  16. package/.claude/commands/TechieFlow/tasks/fix-issues.md +2 -2
  17. package/.claude/commands/TechieFlow/tasks/generate-html.md +7 -3
  18. package/.claude/commands/TechieFlow/tasks/handoff-phase.md +20 -18
  19. package/.claude/commands/TechieFlow/tasks/metrics-report.md +2 -0
  20. package/.claude/commands/TechieFlow/tasks/mockups.md +1 -1
  21. package/.claude/commands/TechieFlow/tasks/productguide.md +2 -2
  22. package/.claude/commands/TechieFlow/tasks/render-workflow-docs.md +1 -1
  23. package/.claude/commands/TechieFlow/tasks/triage-issues.md +2 -2
  24. package/.claude/commands/TechieFlow/tasks/verify-phase.md +1 -1
  25. package/.opencode/plugin/techieflow.js +181 -9
  26. package/.tfcore/agents/analyst.md +5 -8
  27. package/.tfcore/agents/architect.md +1 -10
  28. package/.tfcore/agents/flow-master.md +1 -0
  29. package/.tfcore/agents/verifier.md +1 -0
  30. package/.tfcore/hooks/block-git.sh +4 -2
  31. package/.tfcore/hooks/guard-build.sh +5 -1
  32. package/.tfcore/hooks/guard-db.sh +6 -4
  33. package/.tfcore/hooks/guard-metrics.sh +13 -1
  34. package/.tfcore/hooks/guard-status-html.sh +86 -2
  35. package/.tfcore/hooks/guard-verify-deps.sh +124 -0
  36. package/.tfcore/hooks/guard-verify.sh +8 -3
  37. package/.tfcore/hooks/sweep-artifacts.sh +46 -0
  38. package/.tfcore/routing.yaml +61 -0
  39. package/.tfcore/standards/owner-words.txt +23 -0
  40. package/.tfcore/tasks/_owner-language.md +27 -0
  41. package/.tfcore/tasks/_smoke-test-policy.md +1 -1
  42. package/.tfcore/tasks/_status-update-gate.md +4 -3
  43. package/.tfcore/tasks/amend-docs.md +6 -5
  44. package/.tfcore/tasks/build-phase.md +1 -1
  45. package/.tfcore/tasks/create-deep-research-prompt.md +4 -0
  46. package/.tfcore/tasks/create-doc.md +4 -0
  47. package/.tfcore/tasks/create-project-brief.md +22 -0
  48. package/.tfcore/tasks/day1-brownfield.md +3 -3
  49. package/.tfcore/tasks/day1-greenfield.md +3 -3
  50. package/.tfcore/tasks/facilitate-brainstorming-session.md +4 -0
  51. package/.tfcore/tasks/fix-issues.md +2 -2
  52. package/.tfcore/tasks/generate-html.md +7 -3
  53. package/.tfcore/tasks/handoff-phase.md +20 -18
  54. package/.tfcore/tasks/metrics-report.md +2 -0
  55. package/.tfcore/tasks/mockups.md +1 -1
  56. package/.tfcore/tasks/productguide.md +2 -2
  57. package/.tfcore/tasks/render-workflow-docs.md +1 -1
  58. package/.tfcore/tasks/triage-issues.md +2 -2
  59. package/.tfcore/tasks/verify-phase.md +1 -1
  60. package/.tfcore/telemetry/SCHEMA.md +61 -1
  61. package/.tfcore/telemetry/install-metrics.sh +3 -2
  62. package/.tfcore/telemetry/tf-metrics.sh +435 -21
  63. package/.tfcore/templates/v4custom/app-agents-md-tmpl.md +6 -0
  64. package/.tfcore/templates/v4custom/app-brd-tmpl.md +5 -3
  65. package/.tfcore/templates/v4custom/app-brief-tmpl.md +65 -0
  66. package/.tfcore/templates/v4custom/app-decision-request-tmpl.md +85 -0
  67. package/.tfcore/templates/v4custom/app-library-feedback-tmpl.md +86 -31
  68. package/.tfcore/templates/v4custom/app-phase-brd-tmpl.md +94 -0
  69. package/.tfcore/templates/v4custom/app-phase-uidesign-tmpl.md +60 -0
  70. package/.tfcore/templates/v4custom/app-uidesign-tmpl.md +4 -2
  71. package/.tfcore/templates/v4custom/build-subagent-prompt.md +2 -2
  72. package/.tfcore/templates/v4custom/html-render-shell.md +4 -2
  73. package/.tfcore/utils/__pycache__/tf-brd-status.cpython-312.pyc +0 -0
  74. package/.tfcore/utils/__pycache__/tf-checklist-edit.cpython-312.pyc +0 -0
  75. package/.tfcore/utils/__pycache__/tf-day1-files.cpython-312.pyc +0 -0
  76. package/.tfcore/utils/__pycache__/tf-devguide-list.cpython-312.pyc +0 -0
  77. package/.tfcore/utils/__pycache__/tf-doc-check.cpython-312.pyc +0 -0
  78. package/.tfcore/utils/__pycache__/tf-log-miss.cpython-312.pyc +0 -0
  79. package/.tfcore/utils/__pycache__/tf-misses-md.cpython-312.pyc +0 -0
  80. package/.tfcore/utils/__pycache__/tf-mockups-locate.cpython-312.pyc +0 -0
  81. package/.tfcore/utils/__pycache__/tf-opencode-audit.cpython-312.pyc +0 -0
  82. package/.tfcore/utils/__pycache__/tf-perf-grade.cpython-312.pyc +0 -0
  83. package/.tfcore/utils/__pycache__/tf-render-html.cpython-312.pyc +0 -0
  84. package/.tfcore/utils/__pycache__/tf-split-brd.cpython-312.pyc +0 -0
  85. package/.tfcore/utils/__pycache__/tf-status-facts.cpython-312.pyc +0 -0
  86. package/.tfcore/utils/__pycache__/tf-triage.cpython-312.pyc +0 -0
  87. package/.tfcore/utils/__pycache__/tf-verify-list.cpython-312.pyc +0 -0
  88. package/.tfcore/utils/__pycache__/tf-verify-verdict.cpython-312.pyc +0 -0
  89. package/.tfcore/utils/tf-assets-browser.mjs +96 -0
  90. package/.tfcore/utils/tf-assets.sh +97 -12
  91. package/.tfcore/utils/tf-brd-status.py +14 -5
  92. package/.tfcore/utils/tf-build-list.py +99 -11
  93. package/.tfcore/utils/tf-build-list.sh +5 -3
  94. package/.tfcore/utils/tf-build.sh +88 -15
  95. package/.tfcore/utils/tf-ci-repro.py +685 -0
  96. package/.tfcore/utils/tf-ci-repro.sh +24 -0
  97. package/.tfcore/utils/tf-devguide-list.py +47 -22
  98. package/.tfcore/utils/tf-doc-check.py +242 -10
  99. package/.tfcore/utils/tf-doc-tests.sh +79 -0
  100. package/.tfcore/utils/tf-emit.sh +413 -19
  101. package/.tfcore/utils/tf-feedback.sh +13 -0
  102. package/.tfcore/utils/tf-fix-close.sh +113 -31
  103. package/.tfcore/utils/tf-gitignore-audit.sh +50 -3
  104. package/.tfcore/utils/tf-goal.sh +105 -18
  105. package/.tfcore/utils/tf-harness.sh +9 -4
  106. package/.tfcore/utils/tf-lock.sh +29 -0
  107. package/.tfcore/utils/tf-log-miss.py +34 -8
  108. package/.tfcore/utils/tf-login.mjs +167 -0
  109. package/.tfcore/utils/tf-misses-md.py +24 -21
  110. package/.tfcore/utils/tf-misses-md.sh +5 -4
  111. package/.tfcore/utils/tf-mockup-parity.mjs +427 -63
  112. package/.tfcore/utils/tf-mockup-parity.sh +14 -2
  113. package/.tfcore/utils/tf-model-pick.sh +475 -0
  114. package/.tfcore/utils/tf-owner-text.py +233 -0
  115. package/.tfcore/utils/tf-owner-text.sh +14 -0
  116. package/.tfcore/utils/tf-phase.sh +33 -1
  117. package/.tfcore/utils/tf-portable.sh +230 -0
  118. package/.tfcore/utils/tf-render-html.py +80 -2
  119. package/.tfcore/utils/tf-routing-bind.sh +87 -1
  120. package/.tfcore/utils/tf-routing.sh +7 -0
  121. package/.tfcore/utils/tf-selfcheck.sh +356 -0
  122. package/.tfcore/utils/tf-split-brd.py +17 -2
  123. package/.tfcore/utils/tf-status-evidence.sh +11 -9
  124. package/.tfcore/utils/tf-status-facts.py +133 -44
  125. package/.tfcore/utils/tf-triage.py +62 -16
  126. package/.tfcore/utils/tf-triage.sh +2 -0
  127. package/.tfcore/utils/tf-verify-boot.sh +263 -43
  128. package/.tfcore/utils/tf-verify-emit.sh +20 -0
  129. package/.tfcore/utils/tf-verify-env.sh +33 -4
  130. package/.tfcore/utils/tf-verify-list.py +75 -8
  131. package/.tfcore/utils/tf-verify-screens.mjs +254 -43
  132. package/.tfcore/utils/tf-verify-screens.sh +18 -4
  133. package/.tfcore/utils/tf-verify-tests.sh +272 -28
  134. package/.tfcore/utils/tf-verify-verdict.py +59 -11
  135. package/.tfcore/utils/tf_defect.py +27 -0
  136. package/.tfcore/utils/tf_feedback.py +209 -0
  137. package/.tfcore/utils/tf_roadmap.py +35 -0
  138. package/README.md +19 -5
  139. package/docs/TechieFlow-Installation.md +5 -3
  140. package/opencode.jsonc +24 -0
  141. package/package.json +1 -1
  142. package/scripts/install.mjs +4 -0
  143. package/.tfcore/templates/architecture-tmpl.yaml +0 -650
  144. package/.tfcore/templates/brownfield-architecture-tmpl.yaml +0 -476
  145. package/.tfcore/templates/competitor-analysis-tmpl.yaml +0 -306
  146. package/.tfcore/templates/front-end-architecture-tmpl.yaml +0 -218
  147. package/.tfcore/templates/fullstack-architecture-tmpl.yaml +0 -823
  148. package/.tfcore/templates/market-research-tmpl.yaml +0 -252
  149. package/.tfcore/templates/project-brief-tmpl.yaml +0 -221
  150. package/.tfcore/utils/techieflow-doc-template.md +0 -325
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env bash
2
+ # TechieFlow PreToolUse hook — a verify run may START a dependency, never CREATE one,
3
+ # and never point the application at a different one.
4
+ #
5
+ # TfLens, 2026-09-01 (MISS-TfLens-20260901-02). The configured dev database was refusing
6
+ # connections. The agent ran `docker compose up -d db || docker compose up -d` — the
7
+ # service is named `postgres`, so the `||` fallback executed the BARE compose command and
8
+ # started every service, creating an application container and image the owner had to
9
+ # delete by hand. It then exported the connection-string variable to point the whole test
10
+ # suite at a different PostgreSQL and reported "689/689 pass" against it.
11
+ #
12
+ # Both halves are the same error. A verify run's entire product is trustworthy verdicts,
13
+ # and verdicts measured against a system nobody chose are not weaker evidence — they are
14
+ # evidence about a DIFFERENT system, reported under the checklist's name. The empty
15
+ # substitute database then produced RENDER-EMPTY on nine controls whose real cause was
16
+ # "no data", which is the plausible-wrong-number failure this framework exists to prevent,
17
+ # arriving inside the verifier itself.
18
+ #
19
+ # §1 was already strict about unasked-for FILES (tests/.artifacts/, guard-artifacts.sh) and
20
+ # silent about unasked-for INFRASTRUCTURE. A container, a volume and an image are exactly
21
+ # as much machine state as a stray directory. This hook is that rule, as a rule and not a
22
+ # paragraph (maintenance contract 3).
23
+ #
24
+ # REFUSES:
25
+ # - `docker compose up` / `docker-compose up` with no service named
26
+ # - any `|| docker compose up` fallback, which widens the command precisely when it failed
27
+ # - `docker compose run|create`, `docker run`, `docker volume create` — creating, not starting
28
+ # - an inline or exported connection-string variable in front of a test/run command
29
+ # ALLOWS: `docker start <name>`, `docker compose up <service>`, `docker compose start`,
30
+ # `docker ps|logs|inspect`, and anything that is not one of the above.
31
+ #
32
+ # Wired in .claude/settings.json -> hooks.PreToolUse (matcher "Bash"); OpenCode via
33
+ # .opencode/plugin/techieflow.js. Exit 2 + stderr = block and feed the message back.
34
+ # Fails OPEN (exit 0) if python3 or parseable JSON is unavailable — a guard that cannot
35
+ # read its input must not stop the run.
36
+ #
37
+ # Tested by tests/regression/run.sh tf_013.
38
+
39
+ INPUT="$(cat)"
40
+ command -v python3 >/dev/null 2>&1 || exit 0
41
+
42
+ TF_HOOK_INPUT="$INPUT" python3 - <<'PY'
43
+ import json, os, re, sys
44
+
45
+ try:
46
+ data = json.loads(os.environ.get("TF_HOOK_INPUT", ""))
47
+ except Exception:
48
+ sys.exit(0)
49
+
50
+ cmd = (data.get("tool_input") or {}).get("command")
51
+ if not isinstance(cmd, str) or not cmd.strip():
52
+ sys.exit(0)
53
+
54
+ def block(what, instead):
55
+ print("BLOCKED by TechieFlow policy: %s\n"
56
+ "A verify run may START a service the project already defines; it may not CREATE "
57
+ "one, and it may never measure the application against a different instance — a "
58
+ "green suite against the wrong database is worse than a red one, because it is "
59
+ "quotable.\n%s\n"
60
+ "If the dependency is down and you cannot start the project's own definition of "
61
+ "it BY NAME, stop and ask, naming the one command the owner should run. Record "
62
+ "the resolved target (host, port, database — never credentials) in the verify "
63
+ "report, so which system was measured is on the face of it."
64
+ % (what, instead), file=sys.stderr)
65
+ sys.exit(2)
66
+
67
+ # --- creating infrastructure, rather than starting what the project already defines ------
68
+ COMPOSE = r"docker(?:\s+compose|-compose)"
69
+
70
+ # a bare `up`: no service name before the end of the segment. Flags are not service names.
71
+ for seg in re.split(r"(?:\|\||&&|;|\||\n)", cmd):
72
+ seg = seg.strip()
73
+ m = re.search(COMPOSE + r"\s+up\b(.*)$", seg, re.I)
74
+ if m:
75
+ rest = m.group(1)
76
+ # drop flags and their values; whatever is left is a service name
77
+ words = [w for w in re.split(r"\s+", rest.strip()) if w]
78
+ svc = []
79
+ skip = False
80
+ for w in words:
81
+ if skip:
82
+ skip = False
83
+ continue
84
+ if w.startswith("-"):
85
+ if "=" not in w and w in ("--scale", "--timeout", "--project-name", "-p", "--file", "-f"):
86
+ skip = True
87
+ continue
88
+ svc.append(w)
89
+ if not svc:
90
+ block("`%s` starts EVERY service in the compose file." % seg[:120],
91
+ "Name the service: `docker compose up -d <service>` — and check the name, "
92
+ "because a `|| docker compose up` fallback runs the bare command exactly "
93
+ "when the named one was wrong.")
94
+
95
+ if re.search(r"\|\|\s*" + COMPOSE + r"\s+up\b", cmd, re.I):
96
+ block("a `|| docker compose up` fallback widens the command when the named service failed.",
97
+ "Drop the fallback. If the named service does not exist, the name is wrong — fix "
98
+ "the name or ask; do not start everything instead.")
99
+
100
+ if re.search(COMPOSE + r"\s+(?:run|create)\b", cmd, re.I) or \
101
+ re.search(r"\bdocker\s+(?:run|create)\b", cmd, re.I) or \
102
+ re.search(r"\bdocker\s+volume\s+create\b", cmd, re.I):
103
+ block("this CREATES container or volume state the owner did not ask for.",
104
+ "Start what the project defines: `docker start <name>` or `docker compose up -d <service>`.")
105
+
106
+ # --- repointing the application at a different instance ----------------------------------
107
+ # The variable is whatever the project named it, so match the SHAPE of a connection string
108
+ # rather than a list of names that would never be complete.
109
+ CONNSTR = r"(?:Host|Server|Data\s*Source|Endpoint)\s*=|(?:postgres|postgresql|mysql|mongodb|mssql|sqlserver|redis)(?:\+srv)?://"
110
+ ASSIGN = r"(?:\bexport\s+|\bset\s+|^|\s|;|&&)([A-Za-z_][A-Za-z0-9_]*)\s*=\s*[\"']?([^\"'\s;&|]*)"
111
+
112
+ for m in re.finditer(ASSIGN, cmd):
113
+ name, val = m.group(1), m.group(2)
114
+ if re.search(CONNSTR, val, re.I) or (re.search(r"conn|db|database|datasource", name, re.I)
115
+ and re.search(r"[=:]//|Host\s*=|Port\s*=", val, re.I)):
116
+ block("`%s` points the application or its tests at a connection string chosen here, "
117
+ "not the one the project is configured with." % name,
118
+ "Use the app's own configured connection. TfLens's own test helper already "
119
+ "carries this rule — \"there is deliberately no default here … so tests and app "
120
+ "can never drift onto different servers again\" — and it cost a day to learn.")
121
+
122
+ sys.exit(0)
123
+ PY
124
+ exit $?
@@ -99,14 +99,19 @@ if ledger is not None:
99
99
  sys.exit(0) # a same-day ledger from a framework version before Sitting 4c: date unlocks
100
100
  else:
101
101
  rows = ledger.get("rows") or {}
102
- not_listed = sorted(i for i in introduced if rows.get(i) != "PASS")
102
+ # a ledger kept row by row holds older runs' rows too (Lekhak TF-007): only a row graded
103
+ # today unlocks
104
+ dates = ledger.get("row_dates")
105
+ not_listed = sorted(i for i in introduced if rows.get(i) != "PASS"
106
+ or (isinstance(dates, dict) and str(dates.get(i, "")) != today))
103
107
  if not introduced:
104
108
  # a Verified cell without a readable row id (a malformed line): refuse, nothing can vouch for it
105
109
  not_listed = ["(row id not readable)"]
106
110
  if not not_listed:
107
111
  sys.exit(0)
108
- problem = ("lists these rows as " + ", ".join(f"{i}: {rows.get(i, 'absent')}" for i in not_listed)
109
- + ", not PASS")
112
+ problem = ("lists these rows as " + ", ".join(
113
+ f"{i}: {rows.get(i, 'absent')}" + (f" (graded {dates.get(i)})" if isinstance(dates, dict) and dates.get(i) and dates.get(i) != today else "")
114
+ for i in not_listed) + ", not PASS today")
110
115
 
111
116
  print(
112
117
  "BLOCKED by TechieFlow policy: this write INTRODUCES a `Verified` status, "
@@ -26,6 +26,8 @@
26
26
  # test-results/ test-results-*/ scripts-*/ playwright-report/
27
27
  # The project's own tracked scripts/ is never touched (needs the hyphen).
28
28
  # tests/verify/ (promoted, tracked specs) is never touched (outside the roots).
29
+ # A file under the roots that a test names by path (tests/.artifacts/<folder>/<name>) is kept at
30
+ # any age, with everything below it (Lekhak TF-004); the summary says how many were kept.
29
31
  #
30
32
  # RETENTION: default 7 days. Override per project with `artifactRetentionDays: N`
31
33
  # in .tfcore/core-config.yaml, or per run with TF_ARTIFACT_RETENTION_DAYS=N.
@@ -98,6 +100,42 @@ DAYS = retention_days()
98
100
  CUTOFF = time.time() - DAYS * 86400
99
101
 
100
102
  SWEEP_ROOTS = [os.path.join("tests", ".artifacts"), ".verify"]
103
+
104
+ # ---- what a test names is not litter (Lekhak TF-004) ---------------------------
105
+ # A spec that reads tests/.artifacts/harness/hindi-src lost it on the eighth day, and two rows failed
106
+ # "the crawl produced no result" on a working product. Any path under the sweep roots that a file of
107
+ # the project's tests (or its Playwright config) names is kept, with everything below it, whatever its
108
+ # age. The right home for a fixture is still tests/verify/fixtures/, outside the sweep.
109
+ # Only a NAMED thing inside a folder counts (tests/.artifacts/<folder>/<name>): a folder a test writes
110
+ # into is named with a variable after it (`shots/${name}.png`), which the pattern stops at, and the
111
+ # framework's own output folders are never kept. The Playwright config is not read: it names outputs.
112
+ KEEP_RE = re.compile(r"(?:tests[/\\]+\.artifacts|\.verify)[/\\]+[^'\"`\s)\]},;*?<>|${}+]+")
113
+ OUTPUTS = ("tests/.artifacts/verify/", "tests/.artifacts/build/", "tests/.artifacts/test-results",
114
+ "tests/.artifacts/playwright", "tests/.artifacts/regression", "tests/.artifacts/doc-check/")
115
+ TEXT_EXT = (".ts", ".js", ".mjs", ".cjs", ".cs", ".py", ".json", ".sh", ".cmd", ".ps1", ".yaml", ".yml", ".txt", ".md")
116
+ keep = set()
117
+ def scan_refs(fp):
118
+ try:
119
+ if os.path.getsize(fp) > 2 * 1024 * 1024:
120
+ return
121
+ with open(fp, encoding="utf-8", errors="replace") as fh:
122
+ for m in KEEP_RE.finditer(fh.read()):
123
+ k = re.sub(r"/+", "/", m.group(0).replace("\\", "/")).rstrip("/.")
124
+ if k.count("/") >= (2 if k.startswith(".verify/") else 3) and not (k + "/").startswith(OUTPUTS):
125
+ keep.add(k)
126
+ except Exception:
127
+ pass
128
+ tests_dir = os.path.join(root, "tests")
129
+ if os.path.isdir(tests_dir) and not os.path.islink(tests_dir):
130
+ for dp, dns, fns in os.walk(tests_dir, followlinks=False):
131
+ dns[:] = [d for d in dns if d not in (".artifacts", "node_modules", "bin", "obj", ".git")]
132
+ for f in fns:
133
+ if f.endswith(TEXT_EXT):
134
+ scan_refs(os.path.join(dp, f))
135
+ kept_n = 0
136
+ def kept(fp):
137
+ rel = os.path.relpath(fp, root).replace(os.sep, "/")
138
+ return any(rel == k or rel.startswith(k + "/") for k in keep)
101
139
  LEGACY_ROOT_GLOBS = ["test-results", "test-results-*", "scripts-*", "playwright-report"]
102
140
 
103
141
  removed_files = 0
@@ -162,6 +200,9 @@ if DAYS > 0:
162
200
  except Exception:
163
201
  continue
164
202
  if st.st_mtime < CUTOFF:
203
+ if keep and kept(fp):
204
+ kept_n += 1
205
+ continue
165
206
  rm_file(fp)
166
207
  # remove dirs emptied by this sweep (never the root itself)
167
208
  if dp != top:
@@ -193,6 +234,11 @@ if removed_files or removed_dirs or legacy:
193
234
  f"tests/.artifacts/ and .verify/"]
194
235
  if legacy:
195
236
  parts.append("banned repo-root legacy dirs removed: " + ", ".join(sorted(legacy)))
237
+ if kept_n:
238
+ parts.append(f"kept {kept_n} old file(s) a test names by path (move them to tests/verify/fixtures/)")
196
239
  print("; ".join(parts))
240
+ elif kept_n:
241
+ print(f"TechieFlow sweep-artifacts: kept {kept_n} file(s) older than {DAYS}d because a test names them by path; "
242
+ "move them to tests/verify/fixtures/")
197
243
  PY
198
244
  exit 0
@@ -38,6 +38,8 @@
38
38
  # .opencode/opencode.json). Nothing changes until it runs.
39
39
  # 4. For one unattended run only, pass --model <id> to tf-goal.sh instead; the main agent uses
40
40
  # it, the sub-agents still use the bindings from step 3.
41
+ # 5. When a model's usage limit is reached, the tier's `fallbacks:` list is the answer — see the
42
+ # block below. Nothing is automatic until a limit is actually hit.
41
43
  enabled: true
42
44
  # ---------------------------------------------------------------------------
43
45
  # Tier → model id, per harness. STARTING VALUES — the owner tunes these.
@@ -54,6 +56,65 @@ tiers:
54
56
  claude: haiku
55
57
  opencode: openai/gpt-5.6-luna
56
58
 
59
+ # ---------------------------------------------------------------------------
60
+ # Tier → the models to try INSTEAD, in order, while the tier model is limited.
61
+ # Comma-separated, one line per harness, same flat two-space shape as `tiers:`.
62
+ #
63
+ # WHAT USES IT. `bash .tfcore/utils/tf-model-pick.sh pick <tier> <harness>` returns the first
64
+ # model in "tier model, then this list" that is NOT on cooldown. tf-goal.sh puts a model on
65
+ # cooldown when a cycle ends in a usage limit, re-binds, and starts the next cycle on the next
66
+ # model; tf-routing-bind.sh reads the same answer, so the sub-agents move with the main agent
67
+ # instead of failing behind it. A cooldown expires by itself at the reset time the limit message
68
+ # stated, and the tier goes back to its own model.
69
+ #
70
+ # WHEN IT DOES NOT HELP, stated plainly: on Claude Code the 5-hour and weekly limits are the
71
+ # ACCOUNT's, not the model's, so a fallback to another Claude model is limited too. The supervisor
72
+ # finds that out the honest way — the next cycle hits the same limit, that model goes on cooldown
73
+ # as well, and once the chain is exhausted it sleeps until the reset exactly as it did before.
74
+ # A per-model limit (Opus exhausted while the account is fine) is where the Claude column earns
75
+ # its keep; a provider outage or a monthly balance is where the OpenCode column does.
76
+ #
77
+ # Empty list = no fallback for that tier; the supervisor sleeps. That is the safe default for
78
+ # anyone who does not want a phase silently running on a different model.
79
+ #
80
+ # WHERE THE "limited until <time>" RECORD IS KEPT. In this project, at
81
+ # .tfcore/.session/model-cooldown.json — the framework is installed per project, so its state is
82
+ # per project too, and one project's setting never reaches another. Uncomment the line below to
83
+ # move it: a path relative to the project root, or an absolute one. Several projects pointed at
84
+ # one file learn about a limit from each other instead of each finding it out for themselves.
85
+ # cooldown_file: .tfcore/.session/model-cooldown.json
86
+ # ---------------------------------------------------------------------------
87
+ # The OpenCode lines below are OpenCode Go models (https://opencode.ai/docs/go — a $10/month plan
88
+ # with a per-model monthly allowance, which is exactly the limit these chains exist for). Each tier
89
+ # falls back to a DIFFERENT model, because the allowance that ran out is per model, and then to a
90
+ # different provider, because a whole plan can run out at once.
91
+ fallbacks:
92
+ frontier:
93
+ claude: opus, haiku
94
+ opencode: opencode-go/glm-5.3, opencode-go/kimi-k3, openai/gpt-5.6-sol
95
+ standard:
96
+ claude: haiku
97
+ opencode: opencode-go/mimo-v2.5, opencode-go/qwen3.8-max, openai/gpt-5.6-luna
98
+ economy:
99
+ claude: sonnet
100
+ opencode: opencode-go/deepseek-v4-flash, opencode-go/glm-5.3-flash, openai/gpt-5.6-luna
101
+
102
+ # ---------------------------------------------------------------------------
103
+ # How each harness is PAID FOR. This is what stops one `cost_usd` column pooling
104
+ # three different kinds of number (SCHEMA.md §2.5b).
105
+ # subscription a flat fee buys a quota. Marginal dollars are zero; the unit that means
106
+ # anything is tokens. Claude Max, and any OpenCode provider signed in with OAuth.
107
+ # metered an API key billed per token. The dollars are real money and are summed.
108
+ # local a model on this machine. No quota, no bill.
109
+ # auto work it out per model — OpenCode's own auth.json says oauth or api, and a
110
+ # provider it has never heard of that answers locally is local.
111
+ # `auto` is right for OpenCode because one machine mixes all three at once. Claude Code is
112
+ # declared, because nothing in a transcript says which plan paid for it.
113
+ # ---------------------------------------------------------------------------
114
+ billing:
115
+ claude: subscription
116
+ opencode: auto
117
+
57
118
  # ---------------------------------------------------------------------------
58
119
  # Phase → tier. One line each; values: frontier | standard | economy | inherit.
59
120
  # Rationale per row: docs/Adapter-Design.md §5.6 (the tier map is a HYPOTHESIS
@@ -0,0 +1,23 @@
1
+ # Words the owner should never have to look up, and what to say instead.
2
+ # Read by .tfcore/utils/tf-owner-text.py. One per line: word | say instead
3
+ # A line is added when the owner has had to ask what a word meant, or when the framework's own
4
+ # rules name it (_owner-language.md). Adding a word is cheap; a word the owner knows is a false alarm,
5
+ # so do not add ordinary English or the owner's own vocabulary (parity, checklist, verify, phase).
6
+ oracle | the framework's own script
7
+ denominator | the number you divide by
8
+ numerator | the number being divided
9
+ idempotent | safe to run twice
10
+ invariant | a rule that always holds
11
+ orthogonal | unrelated
12
+ heuristic | a rule of thumb
13
+ canonical | the standard one
14
+ provenance | where the number came from
15
+ cardinality | how many
16
+ semantics | meaning
17
+ deterministic | gives the same answer every time
18
+ tuple | list
19
+ enum | fixed list of values
20
+ rollup | the combined report
21
+ taint | marked unreliable
22
+ short-circuit | stops early
23
+ payload | the data sent
@@ -0,0 +1,27 @@
1
+ # _owner-language — how anything addressed to the owner is written
2
+
3
+ Loaded by every persona. **The shape of a document lives in that document's template, never here.** These are the three rules that apply when no particular document is being written.
4
+
5
+ ## 1. Plain, simple English
6
+
7
+ Everything the owner reads — a terminal reply, a document, a status line, the sentence on a miss — is written for a capable person who has not read one line of this framework.
8
+
9
+ - **No coined terms, no shorthand.** "the framework's own script", not "the oracle". "the number you divide by", not "the denominator". If the owner would have to look a word up, it is the wrong word.
10
+ - **Writing a glossary means the words are wrong.** Change the words. `tf-doc-check.sh` refuses a glossary section.
11
+ - First sentence carries the answer. Name the thing, not its id. Short sentences. Never dramatise.
12
+ - **A command's closing message is checked before the turn can end** (`tf-owner-text.sh`, run by the Stop hook on it and on any free-form document it hands over): no word from `.tfcore/standards/owner-words.txt`; each open upstream problem in a table row saying what it affects and whether it blocks or breaks anything, with the prompt that fixes it; one recorded as fixed upstream called fixed; each command still to run given as the line to paste; and the next prompt in a code block.
13
+
14
+ ## 2. A question for the owner goes in a file, not in the conversation
15
+
16
+ When a command hits a choice only the owner can make and the answer changes what gets built: write `docs/{App}-Decision-Request.md` from `app-decision-request-tmpl.md`, render it with `tf-render-html.sh`, check it with `tf-doc-check.sh`, then say **one line** in the terminal — which file, how many decisions. Nothing else: restating it in the terminal buries the question in the context the file exists to keep clear.
17
+
18
+ Never read a Decision Request back in. The owner's pasted block is the input. In YOLO, take a choice that has a clear recommendation, mark it, and continue; write the file only for one you genuinely cannot take alone.
19
+
20
+ ## 3. Reporting a problem upstream is never refused
21
+
22
+ A gap in the framework or in a library is filed on the day you find it, whatever its size, without asking permission. The shape is in `app-library-feedback-tmpl.md`. Two things bind wherever you are:
23
+
24
+ - **Every entry answers `Blocks:` first — `yes` or `no`.** That word decides whether the run stops.
25
+ - **A non-blocking entry is filed and the work carries on.** No stopping, no asking, no page of analysis mid-run. One entry, then continue, and one line about it when the command ends.
26
+
27
+ A defect goes in the feedback file. A question goes in a Decision Request. Never mixed: different readers.
@@ -12,7 +12,7 @@ A screen passes only if all three hold, at a desktop width and a mobile width:
12
12
 
13
13
  A failure on any of the three is a defect: write it into the row's Remarks (prefix `⚠ visual:` for 2 and 3) and do not report the row done. A smoke earns a row at most `Implemented`; only an executed verify run writes `Verified`.
14
14
 
15
- The evidence of a smoke is the file `bash .tfcore/utils/tf-verify-screens.sh --screen <name>=<route> … --base <url>` writes (`tests/.artifacts/verify/screens.json`, with a screenshot per screen and width); a row is written `Implemented` only after that run, and its Remark names the file. The application is booted with `bash .tfcore/utils/tf-verify-boot.sh start`, which also drives a Blazor Hybrid Windows head; a head the script cannot boot leaves the row below `Implemented` with the reason.
15
+ The evidence of a smoke is the file `bash .tfcore/utils/tf-verify-screens.sh --screen <name>=<route> … --base <url>` writes (`tests/.artifacts/verify/screens.json`, with a screenshot per screen and width); a row is written `Implemented` only after that run, and its Remark names the file. The application is booted with `bash .tfcore/utils/tf-verify-boot.sh start`, which also drives an embedded-browser desktop head Windows head; a head the script cannot boot leaves the row below `Implemented` with the reason.
16
16
 
17
17
  ## Run it yourself
18
18
 
@@ -7,8 +7,9 @@ Steps, in this order:
7
7
  1. `bash .tfcore/utils/tf-status-facts.sh {App} "{command}"` prints today's date, the phase line, the last verified build, the Open requirements section, the Verification log with its new row, the library feedback lines, and the next command in both harness forms. Copy them as printed.
8
8
  2. Write `PROJECT-STATUS.md` with the Write tool in the shape of `.tfcore/templates/v4custom/app-project-status-tmpl.md`: replace every section in place, add none. You write two parts yourself: "Where I am" (at most 80 words, state not story) and "Known blockers". A refused write means the content is mis-shaped: trim it, do not reword it.
9
9
  3. `bash .tfcore/utils/tf-doc-check.sh PROJECT-STATUS.md <every document this command wrote>`; day-1 and `*amend-docs` run `--app {App}` instead, because they own every document. A `FAIL` line means the phase is not closed: fix the document and re-run. A line printed as `OLD` was already there when the command started (the phase marker records them); it does not block and is repaired through `*amend-docs`. Never edit a schema to make a document pass. Documents this command did not write are reported with `--warn`, not fixed here: an older project is repaired through `*amend-docs` when it is next worked on (Schemas §7.1, decision 8).
10
- 4. `bash .tfcore/utils/tf-render-html.sh PROJECT-STATUS.md`, and the same for every human document this command wrote. The checklist is never rendered.
11
- 5. `bash .tfcore/utils/tf-brd-status.sh {App}` rewrites the BRD's Development status table from the checklist and re-renders the BRD.
12
- 6. Append the run record: `.tfcore/tasks/_metrics-emit-gate.md`.
10
+ 4. When this command changed a file under `docs/`, `bash .tfcore/utils/tf-doc-tests.sh <every document it changed>`. A unit test may read a document and guard its text; when one does, this runs the unit tests. `NONE` or `PASS` goes on. `FAIL` means the phase is not closed: put the guarded text back, or, when the change is meant, name the test under "Known blockers" for `*triage-and-fix` to update, since a document command never edits code. `NOT-RUN` is reported as it is printed (Lekhak TF-016).
11
+ 5. `bash .tfcore/utils/tf-render-html.sh PROJECT-STATUS.md`, and the same for every human document this command wrote. The checklist, the miss log and feedback files are never rendered.
12
+ 6. `bash .tfcore/utils/tf-brd-status.sh {App}` rewrites the BRD's Development status table from the checklist and re-renders the BRD.
13
+ 7. Append the run record: `.tfcore/tasks/_metrics-emit-gate.md`.
13
14
 
14
15
  Evidence for every line is the checklist's Requirements Status table and the files on disk, never git. Check a framework file by reading its literal path under `.tfcore/`; search tools skip that folder.
@@ -14,13 +14,14 @@ First: `bash .tfcore/utils/tf-phase.sh start amend-docs {App}` prints the start
14
14
 
15
15
  1. Read the BRD and note the highest `BRD-N`. On a Large project the BRD and checklist are the phase's: `appPhase` in `core-config.yaml` names it, phase 1 is `docs/{App}-BRD.md`, phase n is `docs/{App}-Pn-BRD.md`; the highest id is the highest across every phase. No BRD means no amendment: stop and point at day-1. Note whether the checklist exists.
16
16
  2. Sort every point of the change into ADD (a new capability, actor, screen or integration), MODIFY (an existing item whose behaviour changed, mapped to its `BRD-N`), REMOVE (scope dropped, mapped to its `BRD-N`) or ARCH (a new module, flow, package or decision).
17
- 3. Show the change-set as a numbered table (ADD with the next ids, MODIFY as old to new, REMOVE with the reason, ARCH by decision) and wait for "go" or corrections. This is the only question. In YOLO mode apply it without waiting.
17
+ 3. Show the change-set as a numbered table (ADD with the next ids, MODIFY as old to new, REMOVE with the reason, ARCH by decision) and wait for "go" or corrections. **A table, not an essay: no glossary, no verification chapter, no re-argued history.** This is the only question. In YOLO mode apply it without waiting. If a point of the change turns on something only the owner can decide, do not argue it here — write `docs/{App}-Decision-Request.md` per `.tfcore/tasks/_owner-language.md`, render it, and say one line naming the file and how many decisions it holds.
18
18
  4. BRD. ADD: append a ledger item with the next id, its screen, its mockup link and its acceptance line "When <actor> <does what> on <screen>, then <observable result>"; a new screen gets a row in the Screens and flow table and a Planned row in the Development status table. MODIFY: edit the item in place, same id. REMOVE: `~~BRD-N~~ (removed {date}: reason)`, never deleted. If the additions would take a Small project past 50 requirements, raise it to Medium: `bash .tfcore/utils/tf-day1-files.sh {App} --size M` and the Size in every document header. If they would take a Medium project, or one phase, past 100 requirements or 20 screens, stop and propose a phase split: a new row in `docs/{App}-Phases.md` (written with `--size L` when absent) and a new `docs/{App}-Pn-BRD.md`, instead of growing this one.
19
19
  5. Architecture, when in scope and ARCH items exist: edit the affected sections in place, and add a Decisions log row (date, decision, why, status `planned` naming the BRD item) for every new decision or package. A reversed decision gets a new row; the old row stays.
20
20
  6. Mockups: when a screen was added or changed, run `.tfcore/tasks/mockups.md` with `--update`, so every screen in the BRD has a current mockup before the checklist changes.
21
21
  7. Checklist, only if it exists. ADD: `bash .tfcore/utils/tf-split-brd.sh {App} --add-missing` appends rows for the new items; correct their class. MODIFY: set the rows derived from that item to `Needs re-verify` with a Remark saying what changed. REMOVE: set them to `N/A (removed {date})` and keep the rows. Where the mapping from an item to its rows is unclear, ask, do not guess. If the checklist does not exist yet, the next day-1 stage 2 picks everything up.
22
22
  8. If the amendment changed code-level flows, say that `*devguide {App} --update` is due after the next build.
23
- 9. Decide whether this amendment is a miss: should the original documents plainly have said this (a behaviour that was always required, or two sections that contradicted each other)? Then run `*log-miss {App} "<one sentence>"`. A change of mind or a feature decided today is scope arriving late, not a miss.
24
- 10. `bash .tfcore/utils/tf-doc-check.sh --app {App}`; fix every FAIL.
25
- 11. Run the status gate (`.tfcore/tasks/_status-update-gate.md`) with `"cmd":"amend-docs"`.
26
- 12. Report: items added (ids), modified, removed, the highest id now, what changed in the Architecture, the checklist rows touched, and the next command from the gate.
23
+ 9. Close what this amendment fixed: `bash .tfcore/utils/tf-emit.sh --open-misses {App} --artifact-class doc` lists the open misses whose deficient artifact is a document. Close the ones this amendment resolves in one call: `bash .tfcore/utils/tf-fix-close.sh {App} --misses <id>,<id> --fix-cmd amend-docs --verdict Verified`. Where the mapping from a miss to this amendment is unclear, ask, do not guess. Without this a document miss can never close: `*fix-issues` and `*build-phase` close off checklist rows the verifier touched, which a BRD edit never is.
24
+ 10. Decide whether this amendment is a miss: should the original documents plainly have said this (a behaviour that was always required, or two sections that contradicted each other)? Then run `*log-miss {App} "<one sentence>"`. A change of mind or a feature decided today is scope arriving late, not a miss.
25
+ 11. `bash .tfcore/utils/tf-doc-check.sh --app {App}`; fix every FAIL. Then `bash .tfcore/utils/tf-doc-tests.sh <every document this amendment changed>`: a unit test that reads one of them runs, and a `FAIL` means the amendment removed or changed text a test guards. Put it back, or, when the change is meant, the phase stays open and the report names the test for `*triage-and-fix`; never edit the test here (Lekhak TF-016).
26
+ 12. Run the status gate (`.tfcore/tasks/_status-update-gate.md`) with `"cmd":"amend-docs"`.
27
+ 13. Report: items added (ids), modified, removed, the highest id now, what changed in the Architecture, the checklist rows touched, and the next command from the gate.
@@ -10,7 +10,7 @@ First: `bash .tfcore/utils/tf-phase.sh start build-phase {App}` prints the start
10
10
 
11
11
  ## Steps
12
12
 
13
- 1. `bash .tfcore/utils/tf-build-list.sh {App} --prompts` prints the mode, the working list, the clusters and one sub-agent prompt per cluster. FIX means the verifier or a smoke failed rows: build only those. FRESH means every open row. NOTHING means run the status gate and stop. A row without an acceptance line is refused: fix the checklist first, then re-run.
13
+ 1. `bash .tfcore/utils/tf-build-list.sh {App} --prompts` prints the mode, the working list, the clusters and one sub-agent prompt per cluster. The working list is **every** open row in both FIX and FRESH; FIX only means the rows the verifier or a smoke failed come first. NOTHING means run the status gate and stop. A row without an acceptance line is refused: fix the checklist first, then re-run.
14
14
  2. Spawn every cluster in one turn, each with its printed prompt unchanged: `[trblazeui]` clusters through `/trblazeui`, `[techierag]` through `/techierag`, `[builder]` through the harness's builder sub-agent (`tf-builder` when registered, else the general one). Wait for all of them. A cluster that returns `PARTIAL` is re-spawned with its missing rows. Context pressure is a reason to delegate more, never to stop, and a working list is never shortened: "run build-phase again for the rest" is not an ending.
15
15
  3. A row that cannot be built as written (no mockup, two rows that contradict, a behaviour the BRD plainly needed and never named): take the sensible reading, write it in the row's Remarks, keep building, and log the gap as a `miss` (`.tfcore/tasks/_metrics-emit-gate.md`) with `miss_class` `unspecified-gap` or `spec-contradiction`, `artifact` naming the document, `found_by` `agent-review`, `found_phase` `build-phase`. A library gap goes into `docs/{App}-<Library>-Feedback.md` (from `.tfcore/templates/v4custom/app-library-feedback-tmpl.md`, one file per library) and the row becomes `Blocked`; never a workaround.
16
16
  4. `bash .tfcore/utils/tf-build.sh`: PASS, or FAIL with the real errors (fix them, fanning out by file when there are many), or NOT-RUN naming the rungs tried, which is a host problem and never a blocker. `bash .tfcore/utils/tf-build.sh test` runs the tests.
@@ -276,3 +276,7 @@ CRITICAL: collaborate with the user to develop specific, actionable research que
276
276
  - Balance comprehensiveness with focus
277
277
  - Document assumptions and limitations clearly
278
278
  - Plan for iterative refinement based on initial findings
279
+
280
+ ## Record the run
281
+
282
+ First action of this task: `bash .tfcore/utils/tf-phase.sh start create-deep-research-prompt {App}`. Last action: one `runs.jsonl` record carrying `"cmd":"create-deep-research-prompt"`, written as `.tfcore/tasks/_metrics-emit-gate.md` shows. No status gate here — this command advances no phase. Telemetry has no veto: if the write fails, the command still succeeded.
@@ -99,3 +99,7 @@ User can type `#yolo` to toggle to YOLO mode (process all sections at once).
99
99
  - Select options 2-9 from data/elicitation-methods only
100
100
  - Provide detailed rationale explaining decisions
101
101
  - End with "Select 1-9 or just type your question/feedback:"
102
+
103
+ ## Record the run
104
+
105
+ First action of this task: `bash .tfcore/utils/tf-phase.sh start create-doc {App}`. Last action: one `runs.jsonl` record carrying `"cmd":"create-doc"`, written as `.tfcore/tasks/_metrics-emit-gate.md` shows. No status gate here — this command advances no phase. Telemetry has no veto: if the write fails, the command still succeeded.
@@ -0,0 +1,22 @@
1
+ # create-project-brief
2
+
3
+ `*create-project-brief {App}` writes `docs/{App}-Brief.md`, the one page day-1 reads. It is the cheapest place to be wrong, so it is short and the owner corrects it in two minutes.
4
+
5
+ First: `bash .tfcore/utils/tf-phase.sh start create-project-brief {App}` prints the start time and marks the command running.
6
+
7
+ ## Inputs
8
+
9
+ - `{App}`, or read it from `core-config.yaml`.
10
+ - Whatever the owner gives: a paragraph, a brainstorm result (`docs/brainstorming-session-results.md`), a conversation, or nothing.
11
+
12
+ ## Steps
13
+
14
+ 1. Read `.tfcore/templates/v4custom/app-brief-tmpl.md` — its schema block is the required shape.
15
+ 2. Fill the five sections from what the owner gave. Ask only for what you cannot infer, one round of questions, all at once. In YOLO mode take the sensible reading and mark it.
16
+ 3. **A thing you do not know goes in "Open questions", never into a section as a guess.** Day-1 then asks rather than assumes, which is the whole point of writing this before the Architecture exists.
17
+ 4. Every "Must do" line is an outcome a user gets, numbered, one per line. A line needing a paragraph is two lines.
18
+ 5. Write `docs/{App}-Brief.md`. Never a `-v2`; an amended brief is edited in place.
19
+ 6. `bash .tfcore/utils/tf-doc-check.sh docs/{App}-Brief.md`; fix every FAIL.
20
+ 7. Render it: `bash .tfcore/utils/tf-render-html.sh docs/{App}-Brief.md`. The owner reads the HTML.
21
+ 8. Close: one `runs.jsonl` record carrying `"cmd":"create-project-brief"`, written as `.tfcore/tasks/_metrics-emit-gate.md` shows. No status gate — the project has no checklist yet.
22
+ 9. Report in one line: the file, and how many open questions it carries. Then say the next command is `*day1-greenfield {App}` or `*day1-brownfield {App}`.
@@ -8,7 +8,7 @@ First, before anything else: `bash .tfcore/utils/tf-phase.sh start day1-brownfie
8
8
 
9
9
  1. `{App}` if missing. PascalCase, no spaces; reject anything else and ask again.
10
10
  2. Hints, once: list the markdown files found under `docs/` and at the root (excluding `docs/OldDocs/`, `CLAUDE.md`, `PROJECT-STATUS.md`, and `README.md` unless it holds requirements), then ask: "Reply `all` (or press enter) to harvest all of them, or list the ones to use. Add extra paths or drafting instructions in the same reply. `none` harvests nothing." Parse once: file names into the harvest list, anything else into drafting instructions. Never ask merge-or-new.
11
- 3. The stack: "Which answer set: `dotnet` (`.tfcore/templates/stack-defaults/dotnet.md`), or answer the questions in `.tfcore/templates/stack-questions.md`?" Then only the questions the set leaves open, and only where the code does not already answer them.
11
+ 3. The stack: "Which answer set (the files under `.tfcore/templates/stack-defaults/`), or answer the questions in `.tfcore/templates/stack-questions.md`?" Then only the questions the set leaves open, and only where the code does not already answer them.
12
12
  4. The size: count the routed pages in the code (every route counts, sign-in included; dialogs and tabs are regions of a page) and the roles, then confirm: "Size: Small (up to 10 screens, one role, 50 requirements), Medium (up to 20 screens, 100 requirements) or Large (split into phases)? I count {N} screens and {N} roles, so I propose {X}." Kind is `app`, or `library` for a component or service library.
13
13
 
14
14
  ## Steps, in this order
@@ -19,9 +19,9 @@ First, before anything else: `bash .tfcore/utils/tf-phase.sh start day1-brownfie
19
19
  4. BRD, first half: `docs/{App}-BRD.md` from `app-brd-tmpl.md`: the header (App, Kind, Size, Stack answer set, Status, Date), Summary, Scope, Users and roles, and the Screens and flow table, one row per routed page found in the code. A dialog is a row under its parent screen with `on /route` in the Route column.
20
20
  5. Mockups: run `.tfcore/tasks/mockups.md` for `{App}`. It links the mockups already in `docs/mockups/` to their screens and produces one for every screen that has none, from the code and the running application. Every screen ends with a mockup.
21
21
  6. BRD, second half: the Requirements ledger, one `BRD-N` per thing the verifier will test, each naming its screen, linking its mockup and carrying one acceptance line "When <actor> <does what> on <screen>, then <observable result>". Harvested documents come first: every "the system shall" or "the user can" line becomes an item, attributed, and every table, screen inventory and workflow they hold carries in, never compressed to a one-liner. Then the code: what it already does becomes items too. Mark inferred items `<!-- inferred — please verify -->`. The Non-functional table takes a `perf-budget:` only where the owner stated a number, and the logging requirement from the answer set, recorded as met when the scan found it wired. The Development status table has one row per screen with Verified and Open counts from the strongest evidence. If the count would pass the size cap, propose a phase split instead of merging items.
22
- Large: steps 4 to 6 run once per phase of the Phases table, phase 1 in `docs/{App}-BRD.md` and `docs/{App}-UIDesign.md`, phase n in `docs/{App}-Pn-BRD.md` and `docs/{App}-Pn-UIDesign.md`, each header carrying `Phase | n of m` and its own Size, ids running on across phases.
22
+ Large: steps 4 to 6 run once per phase of the Phases table, phase 1 in `docs/{App}-BRD.md` and `docs/{App}-UIDesign.md`, phase n in `docs/{App}-Pn-BRD.md` (from `app-phase-brd-tmpl.md`: this phase's screens and requirements only, linking back to phase 1) and `docs/{App}-Pn-UIDesign.md` (from `app-phase-uidesign-tmpl.md`, the same way), each header carrying `Phase | n of m` and its own Size, ids running on across phases.
23
23
  7. Checklist: run `.tfcore/tasks/split-brd.md` for `{App}` (Large: with `--all-phases`, one checklist per phase). If a phased plan is among the harvested documents, split-brd migrates its statuses; the plan then moves to `docs/OldDocs/`.
24
- 8. Coding Standards: `docs/{App}-Coding-Standards.md` from `app-coding-standards-tmpl.md`. "Standards applied" names `.tfcore/standards/coding-standards-core.md` and the stack file, plus the choices the stack file leaves open. For dotnet the instance-field prefix follows the drift scan of step 3: the dominant style if one reaches 80 percent, else `obj`; a drafting instruction overrides. "Project rules" holds only rules true of this project alone.
24
+ 8. Coding Standards: `docs/{App}-Coding-Standards.md` from `app-coding-standards-tmpl.md`. "Standards applied" names `.tfcore/standards/coding-standards-core.md` and the stack file, plus the choices the stack file leaves open. Where the stack file leaves a naming convention open, it follows the drift scan of step 3: the dominant style if one reaches 80 percent, else the stack file's default; a drafting instruction overrides. "Project rules" holds only rules true of this project alone.
25
25
  9. `bash .tfcore/utils/tf-day1-files.sh {App} --prefix {obj|none}` writes `.editorconfig`, `AGENTS.md` and `CLAUDE.md`.
26
26
  10. `bash .tfcore/utils/tf-gitignore-audit.sh . --fix`. Read its output. Any untracking commands it prints go into your summary for the owner to run; agents never run git.
27
27
  11. Build once through `.tfcore/templates/v4custom/build-invocation-ladder.md`. A real compile error becomes one line under Known blockers; a wrong-rung error never does.
@@ -11,7 +11,7 @@ Ask once each, and nothing per section:
11
11
  1. `{App}` if missing. PascalCase, no spaces.
12
12
  2. The concept: "Describe the app, any length: a sentence, paragraphs, bullets, half-baked notes, comparisons to other apps. You will edit the document afterwards." Read all of it. Never cap or summarise the owner's input.
13
13
  3. Hints, optional: paths to notes or mockups to harvest, and drafting instructions. `none` is fine.
14
- 4. The stack: "Which answer set: `dotnet` (`.tfcore/templates/stack-defaults/dotnet.md`), or answer the questions in `.tfcore/templates/stack-questions.md`?" Then ask only the questions the set leaves open (for dotnet: Q4, and the rendering mode of Q8).
14
+ 4. The stack: "Which answer set (the files under `.tfcore/templates/stack-defaults/`), or answer the questions in `.tfcore/templates/stack-questions.md`?" Then ask only the questions that answer set leaves open — each set names its own.
15
15
  5. The size: count the routed pages in the concept (every page with its own route, sign-in included; dialogs and tabs are regions of a page) and the roles, then ask: "Size: Small (up to 10 screens, one role, 50 requirements), Medium (up to 20 screens, 100 requirements) or Large (split into phases)? I count {N} screens and {N} roles, so I propose {X}." Kind is `app` unless the concept is a library.
16
16
 
17
17
  Then, in this order:
@@ -21,7 +21,7 @@ Then, in this order:
21
21
  8. BRD, first half: `docs/{App}-BRD.md` from `app-brd-tmpl.md`: the header (App, Kind, Size, Stack answer set, Status, Date), Summary, Scope, Users and roles, and the Screens and flow table. A dialog is a row under its parent screen with `on /route` in the Route column.
22
22
  9. Mockups: run `.tfcore/tasks/mockups.md` for `{App}`. It reads the Screens and flow table and produces `docs/{App}-UIDesign.md` and one `docs/mockups/<screen>.html` per screen. An app with no screens records "skipped — no UI".
23
23
  10. BRD, second half: the Requirements ledger, one `BRD-N` per thing the verifier will test, each naming its screen, linking its mockup and carrying one acceptance line "When <actor> <does what> on <screen>, then <observable result>"; the Non-functional table (a `perf-budget:` only where the owner gave a number; the logging requirement from the answer set); the Development status table, one row per screen, all Planned. The concept is the primary source: every feature, actor and constraint in it becomes an item. Mark inferred items `<!-- inferred — please verify -->`. Harvested requirements carry in as items, attributed, none dropped. If the count would pass the size cap, propose a phase split instead of merging items.
24
- Large: steps 8 to 10 run once per phase of the Phases table, phase 1 in `docs/{App}-BRD.md` and `docs/{App}-UIDesign.md`, phase n in `docs/{App}-Pn-BRD.md` and `docs/{App}-Pn-UIDesign.md`, each header carrying `Phase | n of m` and its own Size, ids running on across phases. Every screen gets its mockup now.
24
+ Large: steps 8 to 10 run once per phase of the Phases table, phase 1 in `docs/{App}-BRD.md` and `docs/{App}-UIDesign.md`, phase n in `docs/{App}-Pn-BRD.md` (from `app-phase-brd-tmpl.md`: this phase's screens and requirements only, linking back to phase 1) and `docs/{App}-Pn-UIDesign.md` (from `app-phase-uidesign-tmpl.md`, the same way), each header carrying `Phase | n of m` and its own Size, ids running on across phases. Every screen gets its mockup now.
25
25
  11. `bash .tfcore/utils/tf-doc-check.sh --app {App}`; fix every FAIL.
26
26
  12. Run the status gate (`.tfcore/tasks/_status-update-gate.md`); the run record carries `"cmd":"day1-greenfield","mode":"stage1"`.
27
27
  13. Stop and say: "Stage 1 is complete: BRD, Architecture and mockups are written and rendered. Review them in the HTML files, or edit the markdown. When you approve, run `*day1-greenfield {App} --stage2`. To change a screen, edit the concept and re-run stage 1, or run `*mockups {App} --update`."
@@ -32,7 +32,7 @@ Only with `--stage2`, and only when `docs/{App}-BRD.md` exists. Ask nothing.
32
32
 
33
33
  0. If the owner gave corrections at the review, apply them to the stage-1 documents first (ids never renumbered; `bash .tfcore/utils/tf-doc-check.sh --app {App}` must pass), count them, and after this run's record append a `review` record: `{"kind":"review","phase":"day1-review","reviewed_run_id":"<stage 1 started>","correction_run_id":"<this run's started>","corrections":N,"what":"<one sentence>"}` through `tf-emit.sh misses`.
34
34
  1. Checklist: run `.tfcore/tasks/split-brd.md` for `{App}` (Large: with `--all-phases`, one checklist per phase). The owner never types `*split-brd`.
35
- 2. Coding Standards: `docs/{App}-Coding-Standards.md` from `app-coding-standards-tmpl.md`. "Standards applied" names `.tfcore/standards/coding-standards-core.md` and the stack file, plus the choices the stack file leaves open (for dotnet, the instance-field prefix, default `obj`). "Project rules" stays empty unless the concept demands a rule true of this project alone.
35
+ 2. Coding Standards: `docs/{App}-Coding-Standards.md` from `app-coding-standards-tmpl.md`. "Standards applied" names `.tfcore/standards/coding-standards-core.md` and the stack file, plus the choices the stack file leaves open, taking that file's stated default for each. "Project rules" stays empty unless the concept demands a rule true of this project alone.
36
36
  3. `bash .tfcore/utils/tf-day1-files.sh {App} --prefix {obj|none}` writes `.editorconfig`, `AGENTS.md` and `CLAUDE.md` from their templates.
37
37
  4. UsageGuide: `docs/{App}-UsageGuide.md` from `app-usageguide-tmpl.md`. The Test users table lists the intended accounts, one per role, none created. The Execution guide is at roadmap level, marking commands that depend on projects not yet built. One "How to test" section per screen in navigation order, naming the user, the steps, the expected result and the REQ ids.
38
38
  5. `bash .tfcore/utils/tf-gitignore-audit.sh . --fix`. Read its output. Any untracking commands it prints go into your summary for the owner to run; agents never run git.
@@ -134,3 +134,7 @@ Generate structured document with these sections:
134
134
  - Always ask before switching techniques: "Ready to try a different approach?"
135
135
  - Offer options: "Should we explore this idea deeper or generate more alternatives?"
136
136
  - Respect their process and timing
137
+
138
+ ## Record the run
139
+
140
+ First action of this task: `bash .tfcore/utils/tf-phase.sh start facilitate-brainstorming-session {App}`. Last action: one `runs.jsonl` record carrying `"cmd":"facilitate-brainstorming-session"`, written as `.tfcore/tasks/_metrics-emit-gate.md` shows. No status gate here — this command advances no phase. Telemetry has no veto: if the write fails, the command still succeeded.
@@ -8,8 +8,8 @@ First: `bash .tfcore/utils/tf-phase.sh start fix-issues {App}` prints the start
8
8
 
9
9
  1. Triage first, as `.tfcore/tasks/triage-issues.md` steps 1 to 4: read the evidence, boot (`tf-verify-boot.sh start`), reproduce each issue on its screen with the screens script, map it to its row, and log it with `tf-triage.sh demote` or `new`. Then `bash .tfcore/utils/tf-triage.sh {App} close --started <the step-0 time> --cmd fix-issues` writes the escaped gate records and the misses with the discovery cost. A defect nobody logged has no miss to close, so this step is never skipped.
10
10
  2. `bash .tfcore/utils/tf-build-list.sh {App} --prompts` now prints FIX mode with the demoted rows, their clusters and one builder prompt each. Spawn every cluster in one turn, exactly as `.tfcore/tasks/build-phase.md` step 2 says: `[trblazeui]` through `/trblazeui`, `[techierag]` through `/techierag`, the rest through the builder sub-agent. A library gap goes into the library's feedback file and the row becomes `Blocked`; never a workaround.
11
- 3. `bash .tfcore/utils/tf-build.sh` until PASS, then smoke every fixed screen with `tf-verify-screens.sh --screen …` (`.tfcore/tasks/_smoke-test-policy.md`); a screen that still fails re-enters step 2 for its rows.
12
- 4. Execute `.tfcore/tasks/verify-phase.md` inline, scoped to the touched rows. Only that run writes `Verified`.
11
+ 3. `bash .tfcore/utils/tf-build.sh` until PASS, then smoke every fixed screen with `tf-verify-screens.sh --screen …` (`.tfcore/tasks/_smoke-test-policy.md`); a screen that still fails re-enters step 2 for its rows. When the evidence was a failed CI run, `bash .tfcore/utils/tf-ci-repro.sh` must also print PASS; a local build with warm caches does not prove a CI fix. The report says the fix passed that reproduction and that the owner's next CI run is the final check, never that CI is fixed.
12
+ 4. Execute `.tfcore/tasks/verify-phase.md` inline, scoped to the touched rows, with its own step 0; rows of another phase's checklist are a second verify with `--phase N`. Only that run writes `Verified`.
13
13
  5. `bash .tfcore/utils/tf-verify-boot.sh stop`, then `bash .tfcore/utils/tf-fix-close.sh {App} --started <the step-0 time> --subagents <what was fanned out> --build <pass|fail>`: the fix-issues run record first, then one miss-fix per touched row with the verifier's verdict from the ledger. A row the verifier left below `Verified` stays open with that verdict on its miss-fix.
14
14
  6. Run the status gate (`.tfcore/tasks/_status-update-gate.md`); the run record is the one step 5 wrote. When this run is the last step of a goal, write the sentinel (`.tfcore/tasks/_yolo-mode.md`).
15
15
  7. Report: evidence read, issues by kind, rows fixed and now `Verified`, rows still open and why, library gaps logged, and the next command from the gate.
@@ -1,8 +1,8 @@
1
1
  # generate-html
2
2
 
3
- Convert one or more **human-readable** markdown files to self-contained HTML using the shared shell. Use this when you need to render documents that `*render-workflow-docs` does not cover (the UsageGuide, the DevGuide, library-feedback docs, ad-hoc design notes, legacy/archived docs). Note: suffixed doc variants like `-v2` are banned by the collision policy (day1-brownfield §1.6) — superseded docs live unmodified in `docs/OldDocs/`.
3
+ Convert one or more **human-readable** markdown files to self-contained HTML using the shared shell. Use this when you need to render documents that `*render-workflow-docs` does not cover (the UsageGuide, the DevGuide, ad-hoc design notes, legacy/archived docs). Note: suffixed doc variants like `-v2` are banned by the collision policy (day1-brownfield §1.6) — superseded docs live unmodified in `docs/OldDocs/`.
4
4
 
5
- **NEVER render the checklist to HTML.** The `*-Checklist.md` (and its Requirements Status table) is an **AI-agent working document** — agents read it in markdown. An HTML mirror just burns tokens and drifts from the source. If asked to render a `*-Checklist.md`, decline and explain it's an agent doc; if a stale `*-Checklist.html` exists from before this rule, the user may delete it.
5
+ **NEVER render an agent working document to HTML.** Two are banned by name and `tf-render-html.sh` refuses both with exit 2: the **requirements checklist** `*-Checklist.md` (and its Requirements Status table), and the **miss log** `*-Misses.md`. Agents read them in markdown; an HTML mirror burns tokens and drifts from the source. If asked to render either, decline and explain it is an agent document; if a stale `*-Checklist.html` or `*-Misses.html` exists from before this rule, delete it. The test for any other file: **if the only reader is an agent, it stays markdown.**
6
6
 
7
7
  ## Why this exists
8
8
 
@@ -92,7 +92,7 @@ Per shell §9 checklist, for each rendered file confirm:
92
92
  - No external resource references except the two CDN scripts.
93
93
 
94
94
  **Mermaid validity pass (do this for EVERY diagram — it is the #1 reported bug).** Apply the shell §5.5 self-check to each mermaid block before emitting it:
95
- - Each node/edge/subgraph label that contains anything other than letters, digits, and spaces (i.e. has `(` `)` `/` `&` `:` `,` `[` `]` `{` `}` `#` `@` `<` `>` `|` `"` etc.) MUST be wrapped in double quotes, with the quotes INSIDE the shape brackets (`API["ASP.NET API (v2)"]`, `DB[("SQL Server")]`).
95
+ - Each node/edge/subgraph label that contains anything other than letters, digits, and spaces (i.e. has `(` `)` `/` `&` `:` `,` `[` `]` `{` `}` `#` `@` `<` `>` `|` `"` etc.) MUST be wrapped in double quotes, with the quotes INSIDE the shape brackets (`API["Orders API (v2)"]`, `DB[("Main database")]`).
96
96
  - No node id is a reserved word (lowercase `end`).
97
97
  - If you find a bare label in the source MD, **fix it in the emitted HTML** (quote it) rather than copying through a diagram you know will throw "Syntax error" in the browser. Note any such fix in the output summary so the author can also fix the MD source.
98
98
 
@@ -113,3 +113,7 @@ Print one line per rendered file: the absolute output path. End with: `Open each
113
113
  - [ ] Mermaid validity pass done (shell §5.5): every non-trivial label double-quoted, no `end` node ids, bare labels fixed not emitted
114
114
  - [ ] No agent-facing authoring note (Depth/Mermaid mandate, template how-to) rendered as visible text — leaked ones omitted and reported
115
115
  - [ ] Copy buttons present on every `<pre>` (added by JS, no need to inject manually)
116
+
117
+ ## Record the run
118
+
119
+ First action of this task: `bash .tfcore/utils/tf-phase.sh start generate-html {App}`. Last action: one `runs.jsonl` record carrying `"cmd":"generate-html"`, written as `.tfcore/tasks/_metrics-emit-gate.md` shows. No status gate here — this command advances no phase. Telemetry has no veto: if the write fails, the command still succeeded.