@techierathore/techieflow 1.0.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.
- package/.claude/commands/TechieFlow/agents/analyst.md +97 -0
- package/.claude/commands/TechieFlow/agents/architect.md +84 -0
- package/.claude/commands/TechieFlow/agents/flow-master.md +217 -0
- package/.claude/commands/TechieFlow/agents/verifier.md +72 -0
- package/.claude/commands/TechieFlow/tasks/_metrics-emit-gate.md +138 -0
- package/.claude/commands/TechieFlow/tasks/_smoke-test-policy.md +98 -0
- package/.claude/commands/TechieFlow/tasks/_status-update-gate.md +78 -0
- package/.claude/commands/TechieFlow/tasks/_yolo-mode.md +77 -0
- package/.claude/commands/TechieFlow/tasks/advanced-elicitation.md +117 -0
- package/.claude/commands/TechieFlow/tasks/amend-docs.md +149 -0
- package/.claude/commands/TechieFlow/tasks/author-brd.md +79 -0
- package/.claude/commands/TechieFlow/tasks/build-phase.md +231 -0
- package/.claude/commands/TechieFlow/tasks/create-deep-research-prompt.md +278 -0
- package/.claude/commands/TechieFlow/tasks/create-doc.md +101 -0
- package/.claude/commands/TechieFlow/tasks/day1-brownfield.md +507 -0
- package/.claude/commands/TechieFlow/tasks/day1-greenfield.md +224 -0
- package/.claude/commands/TechieFlow/tasks/devguide.md +224 -0
- package/.claude/commands/TechieFlow/tasks/document-project.md +343 -0
- package/.claude/commands/TechieFlow/tasks/execute-checklist.md +86 -0
- package/.claude/commands/TechieFlow/tasks/facilitate-brainstorming-session.md +136 -0
- package/.claude/commands/TechieFlow/tasks/fix-issues.md +134 -0
- package/.claude/commands/TechieFlow/tasks/generate-html.md +115 -0
- package/.claude/commands/TechieFlow/tasks/handoff-phase.md +126 -0
- package/.claude/commands/TechieFlow/tasks/index-docs.md +173 -0
- package/.claude/commands/TechieFlow/tasks/kb-mode-interaction.md +75 -0
- package/.claude/commands/TechieFlow/tasks/log-miss.md +160 -0
- package/.claude/commands/TechieFlow/tasks/metrics-report.md +143 -0
- package/.claude/commands/TechieFlow/tasks/mockups.md +122 -0
- package/.claude/commands/TechieFlow/tasks/productguide.md +105 -0
- package/.claude/commands/TechieFlow/tasks/refresh-status.md +135 -0
- package/.claude/commands/TechieFlow/tasks/render-workflow-docs.md +117 -0
- package/.claude/commands/TechieFlow/tasks/shard-doc.md +185 -0
- package/.claude/commands/TechieFlow/tasks/split-brd.md +131 -0
- package/.claude/commands/TechieFlow/tasks/triage-issues.md +157 -0
- package/.claude/commands/TechieFlow/tasks/verify-phase.md +579 -0
- package/.claude/commands/generate-html.md +124 -0
- package/.codex/config.toml +46 -0
- package/.codex/hooks.json +63 -0
- package/.codex/rules/techieflow.rules +8 -0
- package/.opencode/command/generate-html.md +129 -0
- package/.opencode/plugin/techieflow.js +350 -0
- package/.tfcore/TOKEN-GUIDE.md +59 -0
- package/.tfcore/agents/analyst.md +97 -0
- package/.tfcore/agents/architect.md +84 -0
- package/.tfcore/agents/flow-master.md +217 -0
- package/.tfcore/agents/verifier.md +72 -0
- package/.tfcore/checklists/architect-checklist.md +438 -0
- package/.tfcore/core-config.yaml +47 -0
- package/.tfcore/data/brainstorming-techniques.md +36 -0
- package/.tfcore/data/elicitation-methods.md +154 -0
- package/.tfcore/data/techieflow-kb.md +807 -0
- package/.tfcore/data/technical-preferences.md +3 -0
- package/.tfcore/enhanced-ide-development-workflow.md +248 -0
- package/.tfcore/hooks/block-git.sh +301 -0
- package/.tfcore/hooks/codex-adapter.py +248 -0
- package/.tfcore/hooks/guard-artifacts.sh +101 -0
- package/.tfcore/hooks/guard-status-html.sh +102 -0
- package/.tfcore/hooks/guard-status.sh +124 -0
- package/.tfcore/hooks/guard-verify.sh +108 -0
- package/.tfcore/hooks/metrics-session.sh +129 -0
- package/.tfcore/hooks/session-pointer.sh +52 -0
- package/.tfcore/hooks/sweep-artifacts.sh +198 -0
- package/.tfcore/install-manifest.yaml +231 -0
- package/.tfcore/routing.yaml +105 -0
- package/.tfcore/tasks/_metrics-emit-gate.md +138 -0
- package/.tfcore/tasks/_smoke-test-policy.md +98 -0
- package/.tfcore/tasks/_status-update-gate.md +78 -0
- package/.tfcore/tasks/_yolo-mode.md +77 -0
- package/.tfcore/tasks/advanced-elicitation.md +117 -0
- package/.tfcore/tasks/amend-docs.md +149 -0
- package/.tfcore/tasks/author-brd.md +79 -0
- package/.tfcore/tasks/build-phase.md +231 -0
- package/.tfcore/tasks/create-deep-research-prompt.md +278 -0
- package/.tfcore/tasks/create-doc.md +101 -0
- package/.tfcore/tasks/day1-brownfield.md +507 -0
- package/.tfcore/tasks/day1-greenfield.md +224 -0
- package/.tfcore/tasks/devguide.md +224 -0
- package/.tfcore/tasks/document-project.md +343 -0
- package/.tfcore/tasks/execute-checklist.md +86 -0
- package/.tfcore/tasks/facilitate-brainstorming-session.md +136 -0
- package/.tfcore/tasks/fix-issues.md +134 -0
- package/.tfcore/tasks/generate-html.md +115 -0
- package/.tfcore/tasks/handoff-phase.md +126 -0
- package/.tfcore/tasks/index-docs.md +173 -0
- package/.tfcore/tasks/kb-mode-interaction.md +75 -0
- package/.tfcore/tasks/log-miss.md +160 -0
- package/.tfcore/tasks/metrics-report.md +143 -0
- package/.tfcore/tasks/mockups.md +122 -0
- package/.tfcore/tasks/productguide.md +105 -0
- package/.tfcore/tasks/refresh-status.md +135 -0
- package/.tfcore/tasks/render-workflow-docs.md +117 -0
- package/.tfcore/tasks/shard-doc.md +185 -0
- package/.tfcore/tasks/split-brd.md +131 -0
- package/.tfcore/tasks/triage-issues.md +157 -0
- package/.tfcore/tasks/verify-phase.md +579 -0
- package/.tfcore/telemetry/SCHEMA.md +678 -0
- package/.tfcore/telemetry/install-metrics.sh +390 -0
- package/.tfcore/telemetry/pre-commit +94 -0
- package/.tfcore/telemetry/tf-metrics.sh +1415 -0
- package/.tfcore/templates/architecture-tmpl.yaml +650 -0
- package/.tfcore/templates/brainstorming-output-tmpl.yaml +156 -0
- package/.tfcore/templates/brownfield-architecture-tmpl.yaml +476 -0
- package/.tfcore/templates/competitor-analysis-tmpl.yaml +306 -0
- package/.tfcore/templates/front-end-architecture-tmpl.yaml +218 -0
- package/.tfcore/templates/fullstack-architecture-tmpl.yaml +823 -0
- package/.tfcore/templates/market-research-tmpl.yaml +252 -0
- package/.tfcore/templates/project-brief-tmpl.yaml +221 -0
- package/.tfcore/templates/v4custom/app-agents-md-tmpl.md +61 -0
- package/.tfcore/templates/v4custom/app-architecture-tmpl.md +127 -0
- package/.tfcore/templates/v4custom/app-brd-tmpl.md +204 -0
- package/.tfcore/templates/v4custom/app-checklist-tmpl.md +90 -0
- package/.tfcore/templates/v4custom/app-claude-md-tmpl.md +33 -0
- package/.tfcore/templates/v4custom/app-devguide-tmpl.md +167 -0
- package/.tfcore/templates/v4custom/app-editorconfig-tmpl.editorconfig +44 -0
- package/.tfcore/templates/v4custom/app-library-feedback-tmpl.md +31 -0
- package/.tfcore/templates/v4custom/app-productguide-tmpl.md +54 -0
- package/.tfcore/templates/v4custom/app-project-status-tmpl.md +98 -0
- package/.tfcore/templates/v4custom/app-uidesign-tmpl.md +48 -0
- package/.tfcore/templates/v4custom/app-usageguide-tmpl.md +67 -0
- package/.tfcore/templates/v4custom/build-invocation-ladder.md +190 -0
- package/.tfcore/templates/v4custom/html-render-shell.md +502 -0
- package/.tfcore/templates/v4custom/metrics-report-template.md +273 -0
- package/.tfcore/templates/v4custom/opencode-operating-contract.md +56 -0
- package/.tfcore/user-guide.md +633 -0
- package/.tfcore/utils/techieflow-doc-template.md +325 -0
- package/.tfcore/utils/tf-assets.sh +310 -0
- package/.tfcore/utils/tf-codex-bind.py +196 -0
- package/.tfcore/utils/tf-codex-telemetry.py +60 -0
- package/.tfcore/utils/tf-emit.sh +1075 -0
- package/.tfcore/utils/tf-gitignore-audit.sh +281 -0
- package/.tfcore/utils/tf-goal.sh +421 -0
- package/.tfcore/utils/tf-harness.sh +160 -0
- package/.tfcore/utils/tf-mockup-parity.mjs +555 -0
- package/.tfcore/utils/tf-mockup-parity.sh +65 -0
- package/.tfcore/utils/tf-opencode-audit.py +126 -0
- package/.tfcore/utils/tf-perf.sh +241 -0
- package/.tfcore/utils/tf-render-html.py +715 -0
- package/.tfcore/utils/tf-render-html.sh +28 -0
- package/.tfcore/utils/tf-routing-bind.sh +216 -0
- package/.tfcore/utils/tf-routing.sh +247 -0
- package/.tfcore/utils/tf-yolo.sh +119 -0
- package/.tfcore/working-in-the-brownfield.md +606 -0
- package/LICENSE +201 -0
- package/README.md +1212 -0
- package/WORKFLOW.html +1986 -0
- package/docs/TechieFlow-Installation.md +299 -0
- package/opencode.jsonc +929 -0
- package/package.json +60 -0
- package/scripts/install.mjs +992 -0
- package/scripts/test-install.mjs +505 -0
- package/scripts/validate.mjs +155 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# TechieFlow model routing — DECLARATION ONLY (docs/Adapter-Design.md §5.2;
|
|
2
|
+
# decision: DECISIONS.md 2026-08-19 §2).
|
|
3
|
+
#
|
|
4
|
+
# enabled: false ⇒ nothing changes anywhere. Phases keep running on whatever
|
|
5
|
+
# model the session runs on, exactly as before this file existed.
|
|
6
|
+
#
|
|
7
|
+
# A phase declares a TIER, never a model. The tiers map resolves a tier to a
|
|
8
|
+
# per-harness model id (Claude Code aliases: opus|sonnet|haiku|inherit|<id>,
|
|
9
|
+
# pinnable via ANTHROPIC_DEFAULT_*_MODEL; OpenCode ids: provider/model, list
|
|
10
|
+
# with `opencode models`; Codex model slugs: list with `codex debug models`).
|
|
11
|
+
# Routing is declared at the harness boundary and
|
|
12
|
+
# OBSERVED by telemetry (runs.jsonl model/tier fields) — it is never enforced
|
|
13
|
+
# mid-turn, because neither harness can switch a running turn's model.
|
|
14
|
+
#
|
|
15
|
+
# Read this file with: bash .tfcore/utils/tf-harness.sh tier <phase>
|
|
16
|
+
# bash .tfcore/utils/tf-harness.sh model <tier>
|
|
17
|
+
# bash .tfcore/utils/tf-harness.sh effort <tier>
|
|
18
|
+
# Parsing contract: two-space indent, one "key: value" per line — keep it flat.
|
|
19
|
+
#
|
|
20
|
+
# When flipped to enabled: true, the harness bindings still have to be emitted
|
|
21
|
+
# (Claude: .claude/commands/tf/<phase>.md wrappers + .claude/agents/tf-*.md;
|
|
22
|
+
# OpenCode: model fields in .opencode/opencode.jsonc) — see Adapter-Design
|
|
23
|
+
# §5.3/§5.4 and the rollout order in §6. Flipping the flag alone changes
|
|
24
|
+
# nothing; that is deliberate.
|
|
25
|
+
|
|
26
|
+
enabled: false
|
|
27
|
+
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
# Tier → model id, per harness. STARTING VALUES — the owner tunes these.
|
|
30
|
+
# OpenCode ids below are from this machine's `opencode models` (opencode-go /
|
|
31
|
+
# Zen gateway); swap for anthropic/* ids if an Anthropic key is configured.
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
tiers:
|
|
34
|
+
frontier:
|
|
35
|
+
claude: opus
|
|
36
|
+
opencode: opencode-go/kimi-k3
|
|
37
|
+
codex: gpt-5.6
|
|
38
|
+
standard:
|
|
39
|
+
claude: sonnet
|
|
40
|
+
opencode: opencode-go/kimi-k2.7-code
|
|
41
|
+
codex: gpt-5.6-terra
|
|
42
|
+
economy:
|
|
43
|
+
claude: haiku
|
|
44
|
+
opencode: opencode-go/deepseek-v4-flash
|
|
45
|
+
codex: gpt-5.6-luna
|
|
46
|
+
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
# Phase → tier. One line each; values: frontier | standard | economy | inherit.
|
|
49
|
+
# Rationale per row: docs/Adapter-Design.md §5.6 (the tier map is a HYPOTHESIS
|
|
50
|
+
# with a measurement attached — rework ratio by tier from runs.jsonl decides).
|
|
51
|
+
# ---------------------------------------------------------------------------
|
|
52
|
+
phases:
|
|
53
|
+
day1-greenfield: frontier
|
|
54
|
+
day1-brownfield: frontier
|
|
55
|
+
author-brd: frontier
|
|
56
|
+
amend-docs: frontier
|
|
57
|
+
mockups: standard
|
|
58
|
+
split-brd: standard
|
|
59
|
+
build-phase: standard
|
|
60
|
+
fix-issues: frontier
|
|
61
|
+
triage-issues: standard
|
|
62
|
+
verify-phase: standard
|
|
63
|
+
devguide: standard
|
|
64
|
+
productguide: economy
|
|
65
|
+
handoff-phase: economy
|
|
66
|
+
refresh-status: economy
|
|
67
|
+
render-workflow-docs: economy
|
|
68
|
+
generate-html: economy
|
|
69
|
+
metrics-report: economy
|
|
70
|
+
|
|
71
|
+
# ---------------------------------------------------------------------------
|
|
72
|
+
# Subagent → tier (builders are where the tokens go — Adapter-Design §5.6).
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
subagents:
|
|
75
|
+
tf-builder: standard
|
|
76
|
+
trblazeui: standard
|
|
77
|
+
techierag: standard
|
|
78
|
+
tf-test-writer: standard
|
|
79
|
+
tf-explorer: economy
|
|
80
|
+
|
|
81
|
+
# ---------------------------------------------------------------------------
|
|
82
|
+
# Tier → reasoning effort (used by Claude Code and Codex; ignored by OpenCode).
|
|
83
|
+
# ---------------------------------------------------------------------------
|
|
84
|
+
effort:
|
|
85
|
+
frontier: high
|
|
86
|
+
standard: medium
|
|
87
|
+
economy: low
|
|
88
|
+
|
|
89
|
+
# ---------------------------------------------------------------------------
|
|
90
|
+
# Escalation — ADVISORY ONLY (ported from AI-First-Playbook model-tiers.yml;
|
|
91
|
+
# decision: DECISIONS.md 2026-08-21). Meaning of the row below: when the SAME
|
|
92
|
+
# REQs have already been through `fix-issues` after_attempts times without
|
|
93
|
+
# reaching Verified, launch the NEXT run on `tier`. It is applied by whoever
|
|
94
|
+
# launches the phase (you, or a wrapper script) by reading the attempt history —
|
|
95
|
+
# `attempt` on runs.jsonl records / the checklist verdict history — BEFORE the
|
|
96
|
+
# run starts. Nothing switches a running phase's model; neither harness can.
|
|
97
|
+
# Read the next attempt number with:
|
|
98
|
+
# bash .tfcore/utils/tf-emit.sh --next-run-attempt fix-issues REQ-UI-009 ...
|
|
99
|
+
# Format: <phase>: (one line) then " after_attempts: <int>" " tier: <tier>".
|
|
100
|
+
# Ignored entirely while enabled: false, like everything else in this file.
|
|
101
|
+
# ---------------------------------------------------------------------------
|
|
102
|
+
escalation:
|
|
103
|
+
fix-issues:
|
|
104
|
+
after_attempts: 2
|
|
105
|
+
tier: frontier
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# _metrics-emit-gate (shared rule — included by every task that emits telemetry)
|
|
2
|
+
|
|
3
|
+
> Sibling of `_status-update-gate.md`. That gate says *a phase is not done until PROJECT-STATUS
|
|
4
|
+
> reflects reality*. This one says *a run that produced evidence and threw it away is a run that
|
|
5
|
+
> half-happened.* Schema: `.tfcore/telemetry/SCHEMA.md` — read it before emitting anything.
|
|
6
|
+
|
|
7
|
+
## The rule
|
|
8
|
+
|
|
9
|
+
**Every task that runs a phase emits ONE `runs.jsonl` record at completion. Every verify pass emits ONE `gates.jsonl` record per REQ it evaluated.**
|
|
10
|
+
|
|
11
|
+
Emission happens in the same turn as the status-gate write, immediately after it — the status gate is the trigger. Both are terminal housekeeping; neither is optional.
|
|
12
|
+
|
|
13
|
+
**But telemetry has no veto.** If an emit fails, silently or otherwise, the phase still succeeded. Never retry, never diagnose, never mention it in your report, never let it change a verdict. `tf-emit.sh` exits 0 no matter what; that is the design, not a bug to work around.
|
|
14
|
+
|
|
15
|
+
## Who writes what
|
|
16
|
+
|
|
17
|
+
| Stream | Written by | When |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `runs.jsonl` | the task itself | once, at phase completion, right after the status gate |
|
|
20
|
+
| `gates.jsonl` | `verify-phase.md` §6a · `triage-issues.md` | one record per REQ evaluated / per REQ demoted |
|
|
21
|
+
| `misses.jsonl` | `verify-phase` · `build-phase` · `triage-issues` · `fix-issues` · `amend-docs` · `log-miss` | `miss` when something was missed; `miss-fix` when it is repaired; `miss-amend` (via `--amend`) when a `null` field is completed later |
|
|
22
|
+
| `sessions.jsonl` | `.tfcore/hooks/metrics-session.sh` (SessionEnd hook) | automatically — **never by an agent** |
|
|
23
|
+
| `commits.jsonl` | the owner's `pre-commit` hook | automatically — **never by an agent** |
|
|
24
|
+
|
|
25
|
+
## Misses — the fourth question (SCHEMA.md §5.5)
|
|
26
|
+
|
|
27
|
+
A `gates.jsonl` record says a REQ failed. A **`misses.jsonl`** record says *what* was missed, *which phase / agent / model* let it through, and — via its `miss-fix` sibling — *what fixing it cost*. It is the only stream that can carry a design-phase miss, because it is the only one not written by the verifier.
|
|
28
|
+
|
|
29
|
+
**Three things make this stream trustworthy, and none of them are your judgement:**
|
|
30
|
+
|
|
31
|
+
1. **`miss_id` is issued, never invented** — `bash .tfcore/utils/tf-emit.sh --next-miss-id`. It is the join key between a `miss` and its `miss-fix`; a collision silently merges two defects into one lifecycle.
|
|
32
|
+
2. **Attribution is looked up, never typed.** You name `origin_phase`, `origin_agent` and (if you found one in `runs.jsonl`) `origin_run_id`. `tf-emit.sh` resolves `origin_model`, `origin_harness` and `origin_confidence` from that run record — and **forces the model to `null` if the lookup fails, overwriting anything you wrote.** Do not put a model name in a miss record. You cannot know which model ran a phase two days ago, and a wrong one corrupts every per-model comparison built on it.
|
|
33
|
+
3. **Cost is copied, never computed.** A `miss-fix` carries only `fix_run_id`; the emitter copies that run's token window and derives `cost_attribution` (`sole` / `shared:<n>` / `none`) from its `reqs_touched`. Never write token counts, dollars, or an attribution yourself.
|
|
34
|
+
|
|
35
|
+
**Collapse before you emit — one defect is ONE miss (SCHEMA.md §5.5.4).** A REQ that fails three verify passes must not produce three misses; that would make the miss count a measure of retry patience rather than of quality.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
bash .tfcore/utils/tf-emit.sh --open-miss REQ-UI-014 # "<miss_id> <miss_class>", or nothing
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If it prints a miss whose `miss_class` matches the one you would record, **emit nothing** — it is the same miss, still open. If the class differs, emit a new one: the REQ is now failing for a different reason, and that is new information.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
MID=$(bash .tfcore/utils/tf-emit.sh --next-miss-id)
|
|
45
|
+
cat <<JSON | bash .tfcore/utils/tf-emit.sh misses
|
|
46
|
+
{"kind":"miss","miss_id":"$MID","req_id":"REQ-UI-014","req_class":"UI",
|
|
47
|
+
"miss_class":"partial-implementation","artifact":"src","severity":"major",
|
|
48
|
+
"why_missed":"insufficient-verify-method",
|
|
49
|
+
"origin_phase":"build-phase","origin_agent":"trblazeui",
|
|
50
|
+
"origin_run_id":"2026-08-26T09:12:40Z",
|
|
51
|
+
"found_by":"gate","found_phase":"verify-phase","found_gate":"render",
|
|
52
|
+
"found_run_id":"<this run's start>","failure_class":"blank-data"}
|
|
53
|
+
JSON
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**`why_missed` — which PRACTICE failed (SCHEMA.md §5.5.6).** `miss_class` names the defect; this names the practice that let it through, and it is the more decision-changing of the two because it says whether your *specification* or your *verification* is the weak one.
|
|
57
|
+
|
|
58
|
+
`missing-checklist-item` (no REQ or acceptance bullet covered it) · `insufficient-verify-method` (acceptance existed; the gate could not catch this class of defect) · `code-audit-limitation` (`⚠ STATIC-ONLY` — never observable) · `ambiguous-acceptance` (two honest readings) · `dependency-not-declared` · **`instruction-ignored`** (a written framework rule existed and was not honoured) · `other`.
|
|
59
|
+
|
|
60
|
+
**Optional — omit it rather than guess.** `null` means "not assessed" and is an honest answer. But on an **escape** (`found_by` ∈ `owner` / `production`) fill it: something got past every gate, and *why nothing caught it* is the whole value of that record. The report warns when an escape arrives without one.
|
|
61
|
+
|
|
62
|
+
**If the record is already on the stream, complete it — do not edit the file:**
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
bash .tfcore/utils/tf-emit.sh --amend MISS-App-20260828-01 why_missed missing-checklist-item
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
That appends a `miss-amend` (SCHEMA.md §5.5.7). It fills a field that is `null` and **refuses to overwrite one that is not**, so it adds to the history without revising it. Only closed-vocabulary judgement fields are amendable; nothing the emitter derives — attribution, tokens, cost — ever is.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
FA=$(bash .tfcore/utils/tf-emit.sh --next-fix-attempt "$MID")
|
|
72
|
+
cat <<JSON | bash .tfcore/utils/tf-emit.sh misses
|
|
73
|
+
{"kind":"miss-fix","miss_id":"$MID","req_id":"REQ-UI-014",
|
|
74
|
+
"fix_run_id":"<the fix run's started>","fix_cmd":"fix-issues","fix_attempt":$FA,
|
|
75
|
+
"verdict_after":"Verified","reopened":false}
|
|
76
|
+
JSON
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**Every field is a closed vocabulary** (`miss_class`, `artifact`, `severity`, `found_by`, `failure_class`, `verdict_after` — SCHEMA.md §5.5). Never a free-text description of what was missed: that is requirement prose and constraint 7 forbids it here as absolutely as anywhere else. The *description* belongs in the checklist Remark, where a human reads it.
|
|
80
|
+
|
|
81
|
+
## How to emit — the only supported form
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
cat <<'JSON' | bash .tfcore/utils/tf-emit.sh runs
|
|
85
|
+
{"kind":"run","app":"TrSetup","cmd":"build-phase","mode":"build",
|
|
86
|
+
"started":"2026-08-08T03:41:02Z","ended":"2026-08-08T04:12:33Z","duration_s":1891,
|
|
87
|
+
"reqs_touched":["REQ-UI-004","REQ-FN-011"],"reqs_count":2,
|
|
88
|
+
"subagents":["trblazeui"],"files_written":14,"build_result":"pass"}
|
|
89
|
+
JSON
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`tf-emit.sh` injects `v`, `ts`, `project_type`, `app`, and `harness` if you leave them out. It validates the JSON and drops anything malformed. **Do not append to a `.jsonl` file with Write, Edit, or `>>`.** One primitive, one code path — that is what keeps the streams parseable.
|
|
93
|
+
|
|
94
|
+
**Never write `harness` yourself.** These task files are shared byte-identically by Claude Code and OpenCode, so you cannot know from the markdown which harness is running you — copying a literal would stamp the wrong one on every record. `tf-emit.sh` detects it (env vars, then the parent process chain) and records `null` when it genuinely cannot tell. Same reasoning applies to `ts`, `project_type`, and `app`: if the primitive can determine it, let it.
|
|
95
|
+
|
|
96
|
+
To get an `attempt` number, ask; never guess:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
bash .tfcore/utils/tf-emit.sh --next-attempt REQ-UI-004 # prints an integer
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Note your `started` timestamp at step 0 of the task**, before you do any work. `date -u +%Y-%m-%dT%H:%M:%SZ`. You cannot reconstruct it at the end, and an invented duration is a fabricated measurement.
|
|
103
|
+
|
|
104
|
+
## The ten constraints — violating any one is a failed emit
|
|
105
|
+
|
|
106
|
+
1. **Agents never run `git` or `gh`** — not to emit, not to read, not to backfill. `.tfcore/hooks/block-git.sh` blocks it and is correct to. The only git-derived stream comes from the owner's own `pre-commit` hook. If you think you need git for a metric, you need a different metric.
|
|
107
|
+
|
|
108
|
+
**`tf-metrics.sh` is owner-run in its `--backfill-*` modes ONLY (narrowed 2026-08-31).** The line this constraint used to carry — that the whole script is owner-run — was **wrong, and it was flagged twice by TfLens before it was fixed** (TF-001's block, then TF-006's), each time correctly. The script's own header has always said `--report` / `--rollup` are **READ-ONLY, no git, no writes**, `has_commit_hook()`'s docstring says *"a filesystem read, never a git call, so `--report` stays agent-safe"*, and `metrics-report.md` §1 has always instructed agents to run exactly those modes. So the constraint contradicted the script, the task that calls it, and itself — and a consuming agent that believed the constraint declined to run a procedure it was entitled to run, and verified by reading code instead.
|
|
109
|
+
|
|
110
|
+
| Mode | Who | Why |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| `--report` · `--rollup` · `--phases` | **agent-safe** | read-only, no git call anywhere in the path |
|
|
113
|
+
| `--backfill-commits` | **owner only** | invokes `git log` |
|
|
114
|
+
| `--backfill-gates` | **owner only** | writes reconstructed history; only the owner decides a repo's past gets synthesised |
|
|
115
|
+
|
|
116
|
+
*(The script lives at exactly `.tfcore/telemetry/tf-metrics.sh` in every installation. It is invisible to Grep/Glob — `.tfcore/` is a hidden, gitignored directory — so confirm it by reading the literal path, never by searching for the name; see `_status-update-gate.md` §"The framework tree is INVISIBLE to search".)*
|
|
117
|
+
2. **Metrics data is tracked by git.** `docs/metrics/` must never land in a `.gitignore` block. If you notice a pattern that would catch it, say so in your report — do not add the pattern, and do not "helpfully" ignore the directory.
|
|
118
|
+
3. **Never write metrics into `PROJECT-STATUS.md`** — `guard-status.sh` will block it, correctly. Same for `<APP>-Checklist.md`: `guard-verify.sh` inspects those writes and a stray metrics edit risks a false block. Telemetry lives in `docs/metrics/` and nowhere else.
|
|
119
|
+
4. **Do not change `docs/.last-verify.json`.** It is the same-day gate ledger `guard-verify.sh` depends on to permit a `Verified` cell. It stays ephemeral, stays gitignored, stays exactly the shape `verify-phase §6` writes today. Telemetry *reads alongside* it; it never replaces it.
|
|
120
|
+
5. **Append-only, schema-versioned.** One JSON object per line, `"v"` on every record. Never rewrite, compact, sort, or de-duplicate a history file. If a record is wrong, the correction is a *new* record, never an edit. **Know which new record**, because "append a correction" is only advice if a kind exists to carry one: a later `gates.jsonl` record supersedes an earlier verdict on the same REQ; a `miss-fix` closes a `miss`; and a field left `null` on a `miss` is completed by a **`miss-amend`** (SCHEMA.md §5.5.7) — `bash .tfcore/utils/tf-emit.sh --amend <miss_id> <field> <value>`, which fills a `null` and refuses to overwrite anything else. **If none of those fits your situation, stop and report it rather than editing the file** — a stream with no legal correction path is a framework defect, and it is worth more as a reported defect than as one silently-edited line. (That is exactly how §5.5.7 came to exist: TfLens hit it, refused to decide alone, and asked.)
|
|
121
|
+
6. **Telemetry fails silently and never blocks.** No emit may fail a build, block a tool call, abort a phase, or print a visible error.
|
|
122
|
+
7. **No secrets, no content, no client data.** IDs, counts, durations, verdicts, and file paths — that is the whole permitted vocabulary. Never requirement text, prompt text, file contents, commit subjects, or anything from a `docs/` document body. This framework runs on employer projects: assume every record could become public. `failure_class` is a closed enum for exactly this reason — **never** write a free-text description of a failure.
|
|
123
|
+
8. **Provenance never merges.** Records you write are live and carry no `backfilled` flag. Only `tf-metrics.sh --backfill-*` writes `backfilled: true`. Never hand-author a backfilled record, and never produce a figure that pools live with backfilled, or `app` with `library`/`docs`, for first-pass rate, gate catch distribution, or escape rate.
|
|
124
|
+
9. **Never invent a field.** If it is not in `SCHEMA.md`, it does not get emitted. If a field seems genuinely needed, add it to the schema first, with a rationale, then use it.
|
|
125
|
+
10. **Never name a model, a token count, a dollar figure, a cost attribution, or a subagent COUNT.** `model`, `models`, **`model_tokens_out`**, every `tokens_*` field, **`subagent_runs`**, **`tokens_out_subagents`**, `cost_usd`, `tokens_scope`, `routed` on a `runs`/`gates` record; `origin_model` / `origin_harness` / `origin_confidence` on a `miss`; and every cost field on a `miss-fix` — all are resolved by `tf-emit.sh` from the run window or the run you point it at.
|
|
126
|
+
**You still write `subagents`** (§2, the list of *kinds* you invoked) — that is a fact about your own turn and nobody else can know it. You do **not** write `subagent_runs`: the emitter counts the subagent transcripts that actually produced output inside the run's window, and where the two disagree the measured one is right (SCHEMA.md §2.6). A self-reported fan-out count would be the same class of error as a self-reported harness, with the same invisible consequence.
|
|
127
|
+
|
|
128
|
+
You supply `started`, `ended`, `origin_run_id` and `fix_run_id`; the emitter supplies the rest, or `null`. This is the same rule as `harness` (shared task markdown cannot know it) with a sharper consequence — **a per-model miss rate built from a guessed attribution is a routing decision made on invented evidence, and nothing in the output reveals that it happened.**
|
|
129
|
+
|
|
130
|
+
The one thing you must get right for any of it to work: **note `started` at step 0, before you do any work.** Every token, model, cost and fan-out figure is windowed on `[started, ended]`. A `started` reconstructed at the end is a fabricated measurement, and it silently mis-attributes another phase's tokens to this one.
|
|
131
|
+
|
|
132
|
+
## Do not
|
|
133
|
+
|
|
134
|
+
- Do not estimate, interpolate, or infer a value that was not measured. A missing number is emitted as `null` and reported as missing. `null` is an honest answer; a plausible number is not.
|
|
135
|
+
- Do not shell out to compute `files_written` — it is a count you already know.
|
|
136
|
+
- Do not emit a `runs` record for work you did not do (a phase that halted at step 1 emits `build_result: "not-run"`, not a fabricated success).
|
|
137
|
+
- Do not emit per-feature timing. The unit of work here is **the run**, not the ticket, and that is deliberate.
|
|
138
|
+
- Do not mention telemetry in your user-facing report unless something was genuinely notable. It is instrumentation, not a deliverable.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# _smoke-test-policy (shared rule — included by every task that builds or verifies code)
|
|
2
|
+
|
|
3
|
+
## The rule
|
|
4
|
+
|
|
5
|
+
**Every code change is SMOKE-TESTED by the agent that made it, in this same session, BEFORE it is handed to the verifier or reported as "done".** A green `dotnet build` is NOT a smoke test — it proves the code compiles, not that the feature runs. No build phase chains to the verifier, and no agent says "implemented / done", with un-smoke-tested code. The owner should never have to discover at UAT that a feature was never actually run once.
|
|
6
|
+
|
|
7
|
+
A smoke test = boot the app (or the relevant host), exercise the changed feature once against the running app, and confirm it reaches the user without an unhandled exception. The per-phase tasks define the exact shape (`build-phase §6`, `fix-issues`, `devguide §5a`, `verify-phase`). This file defines the things every one of them must honor: **you run it yourself**, **you confirm the data actually renders**, **you confirm the screen actually looks right**, and **you use real test users**.
|
|
8
|
+
|
|
9
|
+
## "It runs" means the CONTROLS RENDER THEIR DATA *and* the screen LOOKS RIGHT — not just HTTP 200
|
|
10
|
+
|
|
11
|
+
A screen passes the smoke only if it clears **two** gates. Both have shipped real, damaging bugs:
|
|
12
|
+
|
|
13
|
+
**RENDER-TRUTH — the data is actually there.** A page that loads without an exception but shows a **blank table, a count badge over zero visible rows, an empty chart, or a blank value** is a FAILED smoke, not a pass (a home page whose details table is empty and whose list shows "16" over blank rows, shipped because the smoke only checked that the page opened). So:
|
|
14
|
+
- For **every data-bound control on the screen you touched** (grid/table/list, chart, detail/value panel), confirm it actually shows data: **rows present AND cells non-empty** (not just a count), chart/series non-empty, value not blank/placeholder. A control hidden by a `@if (x != null)` guard that never appears is render-empty, not "fine".
|
|
15
|
+
- A render-empty/blank control is a defect: log it to the owning `REQ-*` Remarks and do not report the screen "done"/`Verified`.
|
|
16
|
+
|
|
17
|
+
**VISUAL-TRUTH — the screen actually looks right.** Data being present is necessary but NOT sufficient. A screen where every control has its data but the controls **overlap each other, sit off-screen, are clipped to zero height, the layout is broken, or the UI renders unstyled** is a FAILED smoke — this is the exact "the verifier passed but the running UI is completely broken / controls overlapping" problem the framework exists to catch. So, for the screen you touched, at **desktop and a mobile width**:
|
|
18
|
+
- No two controls overlap (intersecting bounding boxes); every control is in-viewport with non-zero width and height; nothing is clipped or pushed off-canvas.
|
|
19
|
+
- Capture a screenshot and **look at it** — overlapping/stacked text, a broken grid, content overflowing its container, or raw unstyled HTML is a visual FAIL even if the geometry checks pass.
|
|
20
|
+
- ❌ "The data is present, so the screen is fine" is a **BANNED excuse** — a visually broken screen is a failed smoke regardless of data.
|
|
21
|
+
- A visual failure is a defect: log it to the owning `REQ-*` Remarks (prefix `⚠ visual:`) and route the fix to the UI builder (`/trblazeui`); do not report the screen "done"/`Verified`.
|
|
22
|
+
|
|
23
|
+
Where a DevGuide exists (`docs/{AppName}-DevGuide.md`, or the split set under `docs/devguides/`), it lists the controls each screen must render — use it as the per-control checklist. The verifier formalizes both gates: the **render gate** (`verify-phase.md §4a/§6`) and the **visual-truth gate** (`verify-phase.md §4b/§6`). A REQ is `Verified` only when it passes acceptance AND render-truth AND visual-truth.
|
|
24
|
+
|
|
25
|
+
**Performance during a smoke is informational only.** If a REQ you just built declares a `perf-budget:` in its acceptance criteria, you MAY run the harness to catch an obvious regression while the app is already up:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bash .tfcore/utils/tf-perf.sh --base http://localhost:5099 --paths "/,/your/route" \
|
|
29
|
+
--build-config Release --json-out tests/.artifacts/perf/smoke.json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Report a blown budget in your summary so it gets fixed now rather than at verify time. But **a smoke never writes a perf verdict** into the checklist — the §4c grading bands, the Debug/weak-sample preconditions, and the `gates_run` telemetry all belong to an executed verify-phase. Same ceiling as everything else here: `Implemented`, never `Verified`.
|
|
33
|
+
|
|
34
|
+
This is the difference between "the method exists / the page compiled" and "the feature works". Only the latter — data present AND looking right — counts.
|
|
35
|
+
|
|
36
|
+
## If the harness cannot reproduce a construct's failure, the harness cannot sign it off either
|
|
37
|
+
|
|
38
|
+
**A UI construct whose failure mode the harness cannot reproduce is a construct the harness cannot certify.** State it plainly, because the instinct is the opposite one — nine clean reproduction attempts feel like evidence that nothing is wrong, when they are evidence that this harness cannot see whether anything is wrong.
|
|
39
|
+
|
|
40
|
+
The case that produced this rule (TfLens TF-007 companion 2, 2026-08-28): UAT reported a modal dialog leaving the page dimmed and dead. **Nine reproduction attempts in headless Chromium could not produce it.** The resolution was not to keep hunting and not to declare it unreproducible-therefore-fixed — it was to **delete the construct**: the flows became ordinary routes. That is very probably the right general answer.
|
|
41
|
+
|
|
42
|
+
So when a defect is real to the owner and invisible to the harness:
|
|
43
|
+
|
|
44
|
+
1. **Never close it as "could not reproduce."** The owner saw it. `found_by:"owner"` is the most valuable record in the miss stream precisely because a human caught what no gate could.
|
|
45
|
+
2. **Prefer replacing the construct with one the harness can drive.** A modal that becomes a route, an overlay that becomes a page, a portal that becomes inline markup — each trades a little visual ambition for a thing every gate can actually grade. A construct only the human can verify is a construct only the human will ever verify, on every future phase, forever.
|
|
46
|
+
3. **If it must stay, say so where it costs something.** The screen is `⚠ STATIC-ONLY` for that behaviour, the REQ is `NOT-OBSERVABLE` on it, and the miss carries `why_missed:"code-audit-limitation"`. Never a silent `Verified`.
|
|
47
|
+
|
|
48
|
+
Same rule as `PERF-UNMEASURED`, `ASSETS-UNMEASURED` and `MOCKUP-UNGRADEABLE`, arriving from the other direction: **an unmeasured thing is unmeasured, not passed.**
|
|
49
|
+
|
|
50
|
+
## Smoke is NOT verify — a self-smoke's ceiling is `Implemented`
|
|
51
|
+
|
|
52
|
+
Your smoke (this policy) and the verifier gate (`verify-phase.md`) are **different steps by different actors**, even when the same session performs both. However thorough your smoke felt, it earns a REQ **at most `Implemented`** — never `Verified`. `Verified` is written only by an **executed** verify-phase run (chained inline per `build-phase §6b`, or a standalone `*verify`): boot, scoped tests, §4a data-render + §4b visual-truth gates, and the run ledger `docs/.last-verify.json` (verify-phase §6). "I did my own smoke and wrote the verdicts myself" is **self-attestation** — the 2026-07-09 TrSetup failure — and is now blocked **mechanically**: the PreToolUse hook `.tfcore/hooks/guard-verify.sh` rejects any checklist write that introduces `Verified` without a same-day ledger. Writing the ledger without actually running verify-phase's steps is falsifying the audit record.
|
|
53
|
+
|
|
54
|
+
## "I can't run it here" is a BANNED excuse — the environment is already set up
|
|
55
|
+
|
|
56
|
+
The owner did the one-time setup (`WORKFLOW.html §0` on WSL / `§0a` on macOS) precisely so the agent can smoke-test without help. These capabilities are PERMANENTLY available on the host:
|
|
57
|
+
|
|
58
|
+
- **Headless Playwright + Chromium** are available on every supported host (WSL: system libs from the §0 bootstrap; macOS/Linux: nothing beyond Node). Browser smoke tests run **headless** — no GUI, no display server needed. **Never ask the owner to install Playwright** — `verify-phase.md §1` self-provisions it per project (`npm install -D @playwright/test` + `npx playwright install chromium`; the browser binary is a shared per-machine cache, so only the first project pays the download). The same step **gitignores every artifact it creates** (`node_modules/`, `/package.json`, `/package-lock.json`, `tests/.artifacts/`, `test-results/`, `test-results-*/`, `playwright-report/`, `.verify/`, `logs/`, …) — git checkin is the owner's manual job and they must never have to triage machine artifacts; any file YOUR run generates that isn't work product gets its `.gitignore` entry in the same step. **All run artifacts go under `tests/.artifacts/`** — both the output *and* the harness. A smoke run may never create a repo-root sibling for either: no `test-results/` or `test-results-<slug>/`, no `scripts-<slug>/`, no `--output test-results-…`. A throwaway smoke script you write is scratch, not project source: it goes in `tests/.artifacts/harness/`, never in the project's own tracked `scripts/` and never in a root-level `scripts-cluster-x/` of its own. A script that imports the Playwright **library** directly bypasses `playwright.config.ts` entirely, so it must place its captures under `tests/.artifacts/` itself and must never hardcode an absolute path. See `verify-phase.md` §1 (artifact-location rule), which binds every self-smoke exactly as it binds the verifier.
|
|
59
|
+
- **The MAUI / Windows-side dotnet bridge** exists (`build-invocation-ladder.md §B`, rungs #3–#4). Windows-targeted code and MAUI code **build AND run** on the right rung (`cmd.exe /c "dotnet run ..."` / `winrun`). WSL2 forwards `localhost`, so WSL-side Playwright reaches a Windows-side port.
|
|
60
|
+
- **The MAUI mobile/desktop runtime bridge** exists for any app that registers it (`core-config.yaml → runtimeVerification.appium`; one-time host setup `WORKFLOW.html §0b`; driver detail `build-invocation-ladder.md §D`). MAUI **Android** runs on an emulator on the Windows host; MAUI **iOS / Mac Catalyst** run on the LAN Mac — both driven over an **Appium** WebDriver endpoint that returns the same screenshot + element tree the gates consume. Appium is the native analogue of Playwright. The MAUI Windows head keeps its FlaUI/Appium-Windows path.
|
|
61
|
+
|
|
62
|
+
Therefore the following are **NOT acceptable reasons to skip the smoke and push the work onward un-tested.** Each maps to an already-solved capability — saying one of these means you skipped the setup, exactly like logging a wrong-rung build error as a "blocker":
|
|
63
|
+
|
|
64
|
+
- ❌ "I can't run the app on Linux / WSL."
|
|
65
|
+
- ❌ "This app targets Windows, so I can't run it from here."
|
|
66
|
+
- ❌ "It's a MAUI app — MAUI can't run on this system."
|
|
67
|
+
- ❌ "It's an Android / iOS / Mac Catalyst app — I can't run a mobile/desktop head from WSL." (If the app registered an Appium endpoint, drive it; if it didn't, log that it's unregistered and stamp the head `⚠ STATIC-ONLY` — never silently skip.)
|
|
68
|
+
- ❌ "Playwright needs a GUI / there's no browser here."
|
|
69
|
+
- ❌ "I'll let the verifier (or the user) smoke it."
|
|
70
|
+
- ❌ "The build passed, so it's fine."
|
|
71
|
+
- ❌ "It's a multi-service app — the API / DB / LLM endpoint it depends on is down, so I can't run it." (You bring those services up yourself — see below.)
|
|
72
|
+
|
|
73
|
+
**Escalating to the user is the LAST resort, not the first.** If WSL-side `dotnet run` can't be reached, switch to rung #4 (Windows-side) per the build ladder. If Playwright still can't connect after that, follow `verify-phase.md §3a` (try rung #4, try another port, THEN — only then — ask the user to run the two-line recipe and wait for `go`). Never propose a cloud deploy (banned per verify-phase's Local-only policy). You ask the user to boot the app **only after** the ladder genuinely fails — and you still run the smoke yourself once they reply `go`.
|
|
74
|
+
|
|
75
|
+
**A multi-service app does not change this — bring the dependent services up yourself.** When the feature needs an API + a web front-end + a database + an LLM endpoint, a dependent service being down is something you **start**, not a blocker you hand to the owner. Read each dependent project's `appsettings*.json` / launch settings for its configured port and URL, then start EACH service yourself **in dependency order** (DB/LLM endpoint first, then API, then web) via the build ladder before concluding you "can't run it". "The stack is down / it's multi-service" is the same banned excuse as "it can't run on Linux" — already-solved by booting the pieces.
|
|
76
|
+
|
|
77
|
+
**A MAUI mobile head does not change this either — boot the emulator + Appium yourself.** For a MAUI **Android** screen, starting the emulator and the Appium server on the Windows host is YOUR job (run the `runtimeVerification.appium.android.launch` command, e.g. via `winrun`; poll `…/status` until ready — emulators are slow to cold-start, so poll, don't give up). For **iOS / Mac Catalyst**, the LAN Mac's Appium must be reachable (`curl …/status`); that one is a genuine session dependency — if the Mac is down, stamp the head `⚠ STATIC-ONLY` and say so, never a faked pass. Asking the owner is still the LAST resort, after the boot-it-yourself escalation.
|
|
78
|
+
|
|
79
|
+
**Native-head input goes to the app's OWN window — never to "whatever has focus".** When smoking a MAUI head (Windows/Android/iOS/Catalyst), bind the automation session to the app under test by identity (launched **PID → its top-level window handle** on Windows; the app **package/bundle id** on mobile) and interact **element-by-element via `AutomationId`** inside that bound session. Global keyboard/mouse injection (FlaUI `Keyboard.Type`, coordinate clicks, PowerShell `SendKeys`, `adb shell input` outside the app) is **BANNED** — it types into whichever window happens to hold focus (an IDE, a terminal, a different app), which both corrupts the smoke *and* stomps on the owner's desktop. Full discipline (bind → verify focus → element-scoped input → re-resolve after dialogs): `verify-phase.md §3b`.
|
|
80
|
+
|
|
81
|
+
## Git is manual — NEVER run git to inspect code or chase a defect
|
|
82
|
+
|
|
83
|
+
This framework keeps **all** git activity manual: agents never run `git` or `gh` — not to commit, and (outside YOLO) **not to read**. Do NOT reach for `git diff` / `git log` / `git status` / `git blame` to see "what changed" or to investigate a bug while smoking, verifying, observing, or mapping code. **The harness enforces this mechanically**: `.claude/settings.json` (and `opencode.jsonc`) DENY every git/gh **write** subcommand in every permission mode, and the PreToolUse hook `.tfcore/hooks/block-git.sh` blocks git **reads** outside YOLO and compound forms (`cd x && git log`, `bash -c "git …"`) always. **YOLO / goal mode** (`.tfcore/tasks/_yolo-mode.md`, `*yolo`) is the one exception: read-only git/gh is allowed there as supplementary evidence; **writes never are**. A blocked git call is the policy working — do **not** retry with another git form, and do not treat the block as an obstacle to the task: everything you need is local. Investigate by **reading the working-tree files** at their paths: the files on disk ARE the as-built code, and a finding's evidence is the `file:line` you read, never a diff. (`refresh-status` was de-git-ed for exactly this reason — see `WorkFlow-Context.md`; status/recovery is reconstructed from the checklist tables + files-on-disk + a fresh `dotnet build`, never from commit history.) Sub-agent prompts must carry this rule verbatim — library agents (`/trblazeui`, `/techierag`) never read this file.
|
|
84
|
+
|
|
85
|
+
## Test users — use the documented/existing ones; NEVER auto-create random smoke users
|
|
86
|
+
|
|
87
|
+
Smoke and verify runs that create throwaway accounts (`smoketest_user_8472`, `test@test.test`, randomly-named users) **pollute the database** and are banned. The agent has DB access (the connection string lives in `appsettings*.json` / environment config) — use it to find real accounts instead of inventing them. Resolve test credentials in THIS order and stop at the first that works:
|
|
88
|
+
|
|
89
|
+
1. **`docs/{AppName}-UsageGuide.md` → the "Test users" table** is the canonical registry. Use an account listed there (matching the role the feature needs).
|
|
90
|
+
2. **If that account isn't created yet, or there is no UsageGuide:** query the **database directly** with the connection string from config. Read the users/identity table; reuse a suitable existing account. (Read-only — you're looking up credentials, not mutating data.)
|
|
91
|
+
3. **If neither yields a usable account: STOP and ASK the user.** Show what you need and what you'd create, e.g. — *"I need an Admin test user to smoke REQ-FN-7. The DB has no admin account and the UsageGuide lists none. Either give me credentials to use, or confirm I should create: `admin@{app}.test` / `Pass!23` (Admin). Create it? (y/n)"* — and wait. Do not proceed on a guess.
|
|
92
|
+
4. **Only after explicit confirmation,** create the user(s) — then **record them in `docs/{AppName}-UsageGuide.md`'s Test users table** (mark `Created? = ✅`) so the next phase and the verifier reuse the SAME accounts instead of making new ones.
|
|
93
|
+
|
|
94
|
+
NEVER invent a throwaway user mid-smoke. NEVER create accounts without the user's confirmation. The UsageGuide Test-users table is the single source of truth for test accounts — every smoke, every verify, and the human UAT all draw from it, so the DB stays clean and reproducible.
|
|
95
|
+
|
|
96
|
+
## Evidence discipline — state which command actually ran (both harnesses)
|
|
97
|
+
|
|
98
|
+
When reporting a build, smoke, or verify result, name the exact command and where it ran. Distinguish: WSL `dotnet` vs Windows-host build/run through `winrun`/`cmd.exe` vs native Mac vs container; focused tests vs the full solution build; your self-smoke vs an executed verifier run. **Never convert a successful intermediate command into a full workflow pass.** These are incomplete outcomes, not completion: "build is green; run smoke later" · "bridge exists; user can verify it" · "tests passed" when only focused unit tests ran · "full build blocked" because the wrong ladder rung was used before trying the right one. (This section is the harness-neutral doctrine that also appears in `opencode-operating-contract.md` — this file is the canonical copy, loaded by every build/verify task in both harnesses.)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# _status-update-gate (shared rule — included by every checklist-executing task)
|
|
2
|
+
|
|
3
|
+
## The rule
|
|
4
|
+
|
|
5
|
+
**Every agent that executes a checklist or phase MUST update PROJECT-STATUS — BOTH `PROJECT-STATUS.md` AND its rendered `PROJECT-STATUS.html` — as its final action, before reporting "done", before handing back to the user, before chaining to another agent. This is non-negotiable and non-skippable.**
|
|
6
|
+
|
|
7
|
+
A phase is not complete when the build passes or the tests are green. It is complete when PROJECT-STATUS reflects the new reality. **"Update PROJECT-STATUS" always means the markdown AND the HTML — never the `.md` alone.** The owner reads the `.html` to check status; a status update that touches only the markdown leaves the page the human actually looks at stale, which defeats the entire purpose of the gate. If you wrote `PROJECT-STATUS.md` but did not re-render `PROJECT-STATUS.html`, you are NOT finished. If you are about to end your turn and you have not written both, you are not finished.
|
|
8
|
+
|
|
9
|
+
## PROJECT-STATUS is a CRISP, FIXED-SHAPE snapshot — you OVERWRITE it, you NEVER append to it
|
|
10
|
+
|
|
11
|
+
PROJECT-STATUS is a **one-page state snapshot a human reads in ten seconds** — it answers "where is this project and what do I run next?" in plain English. It is **not** a running journal of everything the agents did. It has exactly the sections defined in `.tfcore/templates/v4custom/app-project-status-tmpl.md` and **no others**:
|
|
12
|
+
|
|
13
|
+
- frontmatter only (`project`, `stack`, `last_updated`, `current_phase`, `last_verified_build`, `last_verified_date`)
|
|
14
|
+
- `## Where I am` — ONE short paragraph
|
|
15
|
+
- `## Next command to run` — a command block + at most one line naming the target REQ IDs
|
|
16
|
+
- `## Open requirements` — a bullet list synced to the checklist
|
|
17
|
+
- `## Known blockers`
|
|
18
|
+
- `## Verification log` — a dated **table** (one row per pass), nothing more
|
|
19
|
+
- `## Library feedback summary` · `## Standards compliance` · `## Deferred / future`
|
|
20
|
+
|
|
21
|
+
**Updating PROJECT-STATUS means OVERWRITING the content of these existing sections in place. You do NOT add new sections.** The whole file stays roughly template-length (well under ~60 lines). The detailed blow-by-blow history lives in two places that already exist for it — the **checklist Remarks cells** (per-REQ) and the dated **`.verify/` artifacts** — never here.
|
|
22
|
+
|
|
23
|
+
These are BANNED — they are exactly the disease that turned real status files into 280-line unreadable messes:
|
|
24
|
+
|
|
25
|
+
- ❌ **Adding a per-run prose section** — `## *verify all — formal coverage matrix (2026-06-29)`, `## *fix-issues — …`, `## *build-phase — …`, or any dated narrative of what this run did. Every run that appends such a section makes the file permanently longer; after a week it is an append-log nobody can read. A verify/fix/build run records its outcome as **ONE new row in the `## Verification log` table** plus updated **Remarks in the checklist** — full stop. No new H2 in PROJECT-STATUS.
|
|
26
|
+
- ❌ **Stuffing `current_phase:` (or any frontmatter field) with a paragraph.** `current_phase` is ONE short line: a phase name plus at most a half-line qualifier — e.g. `Verify — 19 open, tail is env/external-blocked`. The detail ("re-booted the stack cold, ran the 55-screen sweep, REQ-UI-010 deep-verified on /ShowKundali/368, 9 tabs …") does NOT belong in frontmatter, in `## Where I am`, or anywhere in this file.
|
|
27
|
+
- ❌ **Preserving old run history.** PROJECT-STATUS shows the CURRENT state only. If a section has already grown past its template shape (multiple dated sections, a giant `current_phase`), **TRIM it back to the template shape as part of your update** — do not carry the old prose forward "to be safe".
|
|
28
|
+
|
|
29
|
+
Smell test: if your edit grows the file by more than the single Verification-log row (and small in-place text changes), you are appending narrative that belongs in the checklist. Stop and move it there.
|
|
30
|
+
|
|
31
|
+
**The harness enforces this shape MECHANICALLY** (same treatment as the git ban): the `.tfcore/hooks/guard-status.sh` PreToolUse hook blocks any Write/Edit to `PROJECT-STATUS.md` that adds an H2 outside the template's fixed section set, adds a heading naming a command run (`*verify` / `*build-phase` / `*fix-issues`), stuffs `current_phase:` past one short line, or writes the file longer than ~120 lines. A blocked status write means *your content is mis-shaped* — trim to the template sections and move the narrative to the checklist Remarks, do NOT retry with the same content under a reworded heading and do NOT split the narrative across several smaller edits to sneak it past the guard.
|
|
32
|
+
|
|
33
|
+
## Never run git to update status
|
|
34
|
+
|
|
35
|
+
Status is reconstructed from the **checklist Requirements Status tables + the working-tree files on disk + a fresh `dotnet build`** — **never** from git. Do NOT run `git grep` / `git diff` / `git log` / `git status` / `git blame` to discover "what changed" for the status write. Everything you need is **local**: read the checklist tables and the source files at their paths (the files on disk ARE the as-built code; `ls -lt` / `find -newer PROJECT-STATUS.md` give you recency). **The harness enforces this**: `.claude/settings.json` DENIES every git/gh **write** in every mode, and the `.tfcore/hooks/block-git.sh` PreToolUse hook blocks git **reads** outside YOLO (and compound forms always) — a blocked git call mid-gate means *use the local evidence path*, not *retry another git form*, and it is NEVER a reason to guess or to pad the status file with narrative: the checklist table alone is sufficient to write every section. (Same rule as `_smoke-test-policy.md` §"Git is manual" and `refresh-status.md`.) **YOLO / goal mode** (`_yolo-mode.md`) unlocks read-only git (`status`/`log`/`diff`/`blame`) as *supplementary* evidence; the checklist table + working tree stay primary, and git writes stay blocked.
|
|
36
|
+
|
|
37
|
+
## The framework tree is INVISIBLE to search — never conclude a framework file is missing
|
|
38
|
+
|
|
39
|
+
`.tfcore/` (and `.claude/`, `.codex/`, `.opencode/`, `.agents/skills/`) are **hidden dot-directories** AND are listed in every app's `.gitignore` framework block — the scaffolders write that block deliberately, because the deployed framework copies are never committed in an app repo (WORKFLOW.html §3). **Two independent filters** therefore hide them from the tools you would otherwise reach for:
|
|
40
|
+
|
|
41
|
+
- **Grep / `rg`** skips hidden paths *and* respects `.gitignore`. It needs **both** — `rg --hidden --no-ignore`, i.e. `rg -uu` — to see `.tfcore/`. `--hidden` alone is NOT enough.
|
|
42
|
+
- **Glob**, `find . -name '…'` with a bare pattern, `git grep`, `git ls-files` — blind for the same reasons. Nothing under `.tfcore/` is tracked in an app repo, so every git-backed search returns zero rows.
|
|
43
|
+
|
|
44
|
+
**A search that returns nothing is therefore NOT evidence of absence.** Every framework file has exactly one canonical path, and the task or doc that needs it names that path. **Check existence by reading the literal path** — `Read .tfcore/telemetry/tf-metrics.sh` — never by searching for the filename. If you genuinely must search the framework tree, `rg -uu`.
|
|
45
|
+
|
|
46
|
+
Before you record a framework file as missing — in a verdict, a checklist Remarks cell, a BRD status row, a blocker, or a report — you MUST have tried the literal path and failed. **"Not present anywhere in this tree", written on the strength of a default Grep, is a false negative that propagates into the docs**, blocks a gate that was never actually blocked, and is inherited as fact by every agent after you.
|
|
47
|
+
|
|
48
|
+
**If a framework file genuinely is absent**, the cause is known and so is the fix: a fresh clone has no `.tfcore/` (it was never committed), so the repo needs `update-framework.sh <repo>` run once **on this machine**. Report exactly that. Do not conclude the framework is uninstalled or unsupported here, and never route around a missing framework file by reimplementing what it does.
|
|
49
|
+
|
|
50
|
+
## What "update PROJECT-STATUS" means (minimum)
|
|
51
|
+
|
|
52
|
+
1. `last_updated: {today YYYY-MM-DD}`.
|
|
53
|
+
2. `current_phase` set to where the project now is — **ONE short line** (phase name + at most a half-line qualifier), never a paragraph of run detail.
|
|
54
|
+
3. `last_verified_build` + `last_verified_date` reflect the most recent build.
|
|
55
|
+
4. **Open requirements** list synced to the checklist's **Requirements Status** table — every REQ not yet `Verified` stays listed.
|
|
56
|
+
5. **Next command to run** updated to the exact next step, expressed **only as a command pointed at a checklist/scope** — e.g. `/TechieFlow:agents:verifier *verify ui` (filters `docs/{AppName}-Checklist.md` to `REQ-UI-*`) or `/TechieFlow:agents:flow-master *build-phase {AppName}` (with both Claude Code and OpenCode forms where they differ). **Do NOT write a prose description of the technical work to do next** — no "next, wire up the X service and fix the Y binding and then add validation to Z". The *what* already lives in the checklist's REQ rows; PROJECT-STATUS only says **which command to run against which checklist/REQs**. If you need to point at specific items, name the REQ IDs (e.g. "resume FAILed `REQ-UI-007`, `REQ-UI-012`"), not a paragraph explaining how to fix them. Keep the whole "Next command to run" section to the command block plus, at most, one line naming the target REQ IDs.
|
|
57
|
+
|
|
58
|
+
**Which command — derive it from the checklist's build state; do NOT freelance.** The pipeline is a strict ladder **Build → Verify → Handoff**, gated on the *weakest* in-scope REQ. Look at the checklist Requirements Status table and pick by the least-advanced open REQ:
|
|
59
|
+
- **Any REQ not yet built** — `Planned` / `In Progress` / `PARTIAL` / `NOT-IMPLEMENTED`, or any open row whose feature isn't implemented yet → the lead command is **`*build-phase {AppName}`** (keep building). **You do NOT lead with `*verify all` while real functionality is still unbuilt** — verifying a half-built app wastes a pass and misrepresents the project as further along than it is. (You may add ONE trailing line noting verification follows, but the headline command is build.) **This tier also covers a built REQ that cannot be verified yet because the test/harness it needs does not exist** (`NOT-OBSERVABLE`, "unit/integration test to be written", no test project) — writing that test is *build* work (`*build-phase` adds unit tests), so build still leads until the REQ is actually observable. Don't send the verifier at a REQ it has no way to assert — it will only bounce back `NOT-OBSERVABLE`.
|
|
60
|
+
- **Every REQ built AND observable (all at least `Implemented`, with a test/route the verifier can actually exercise) but some not yet `Verified`** → now verification is the gating work → lead with **`*verify all {AppName}`** (or the narrowest `*verify ui|functional` scope that covers the unverified rows).
|
|
61
|
+
- **Every agent-verifiable REQ terminal, but open rows remain that are documented OWNER-RUN UAT** (external/host-bound/destructive steps the verifier cannot exercise from this machine — live installs, a physical Mac session, a human eyeball check — listed in the UsageGuide's UAT plan) → phase = **`UAT`**; next command = the owner-run pointer, e.g. `(owner-run) walk docs/{AppName}-UsageGuide.md §"UAT plan"`, naming the open REQ IDs. **Do NOT suggest `*handoff-phase` — not even as "optional".** If a READY-FOR-UAT handoff already ran this cycle (the Verification log has its row), re-suggesting it is noise that reads as "we're done" while rows are still open — the exact overreach the owner rejected (TrSetup, 2026-07-10). Only if handoff has NEVER run for this UAT cycle does `*handoff-phase {AppName}` lead once (it *produces* the UAT bundle); after that the next command is the owner UAT pointer and STAYS there until the owner closes the rows. Never use "done" / "Released" / handoff language while any non-terminal row remains — `Released` is set by the OWNER after UAT, never proposed by an agent.
|
|
62
|
+
- **Every REQ terminal** (`Verified` / `Done (pre-existing)` / `N/A`; library-`Blocked` counts as pass-through) → **`*handoff-phase {AppName}`** (if it has not run yet; if it has, the project is waiting on the owner to set `Released`).
|
|
63
|
+
This is the single rule for choosing the next command — `*build-phase` and `*verify*` are not interchangeable "either works" options; the build state decides which one. When in doubt between build and verify, **build** (an un-built feature is never closed by a verify run).
|
|
64
|
+
|
|
65
|
+
**"Next command = `*build-phase` for the remaining REQs" is NOT a way to end a build pass early (build-phase §2b, owner rule 2026-08-21).** If you are writing this gate at the end of a `*build-phase` run and the reason some REQs are still `Planned` is that *this pass did not get to them*, you are not at the gate — go back and build them (fan out more sub-agents). The build-leads bullet above describes a state found on re-entry (a crashed session, an owner-gated or `Blocked` remainder, FIX mode after verifier failures), never a pass that chose to stop. Under YOLO / goal mode (`_yolo-mode.md`) there is nobody to "run it again".
|
|
66
|
+
6. A new **Verification log** row whose "Status table" column links to the checklist that holds the per-REQ detail (`docs/{AppName}-Checklist.md#requirements-status`) — NOT a dated `docs/qa/*.md` file (those no longer exist).
|
|
67
|
+
7. Library-feedback counts + standards-compliance lines refreshed if the phase touched them.
|
|
68
|
+
8. **HTML refresh (MANDATORY — every time, same turn you edit the `.md`):** re-render `PROJECT-STATUS.html` from the markdown you just wrote — **one command, `bash .tfcore/utils/tf-render-html.sh PROJECT-STATUS.md`** (added 2026-08-27; never hand-author the HTML, never bash-heredoc it — see `.tfcore/tasks/generate-html.md`). This is not optional cleanup and not a "later" step — the owner reads the `.html`, so a markdown-only update is an **incomplete** update that fails this gate. If you edited `PROJECT-STATUS.md` you re-render `PROJECT-STATUS.html` in the same turn, full stop. **The harness enforces this MECHANICALLY** (added 2026-08-25, same treatment as the git ban and the status shape): the `.tfcore/hooks/guard-status-html.sh` **Stop** hook refuses to end your turn while `PROJECT-STATUS.html` is older than `PROJECT-STATUS.md`, or missing (Claude Code and Codex block the stop; OpenCode, which has no blocking Stop hook, sends the same message back into the session as a follow-up prompt when it idles). A blocked stop means *the render is genuinely outstanding* — re-render it, do not look for a way around the hook. **Do NOT render the checklists to HTML** — they are AI-agent working documents kept in markdown only (the per-REQ Requirements Status table is the agent's source of truth, not a human HTML page).
|
|
69
|
+
9. **BRD §4 Development status rollup** (keeps the human BRD snapshot tracking reality). If `docs/{AppName}-BRD.md` has a `## … Development status` section, refresh it from the checklists:
|
|
70
|
+
- One row per feature (each §"Feature catalog" `### F-…` entry). Roll its owned REQs up to a feature-level status: feature → its `Requirements: BRD-…` line → the `REQ-*` those BRDs split into → the per-REQ Status in the checklist tables.
|
|
71
|
+
- Map: **all** owned REQs terminal (`Verified` / `Done (pre-existing)` / `N/A`) → `Done`, 100%; some done + some open → `Partial` with an approximate %; work started but nothing verified (`In Progress`/`Implemented`) → `In progress`; nothing started → `Planned`, 0%; any `Blocked` REQ → keep the feature's computed status and add a short "blocked: …" note.
|
|
72
|
+
- Update ONLY the table cells + the `Snapshot as of {today}` line — touch nothing else in the BRD (no requirement text, feature prose, or BRD-N IDs). Then re-render `docs/{AppName}-BRD.html` via `generate-html.md`.
|
|
73
|
+
- **If the BRD has no Development status section** (a BRD authored before this section existed): do NOT do section surgery inside a build phase — leave the BRD untouched and add one line to your phase report: "BRD has no §4 Development status section — run `*refresh-status {AppName}` once to add it." (`refresh-status` owns the insert + renumber.)
|
|
74
|
+
10. **Emit the run record** (`.tfcore/tasks/_metrics-emit-gate.md`). The status gate is also the telemetry trigger: in the same turn you write PROJECT-STATUS, append ONE `runs.jsonl` record for the phase you just finished — `cat <<'JSON' | bash .tfcore/utils/tf-emit.sh runs`. This is what turns a run into durable history instead of a status cell that the next run overwrites. **Telemetry has no veto:** the emit cannot fail your phase, cannot block a write, and is never worth retrying or reporting. Never put metrics *into* PROJECT-STATUS — `guard-status.sh` will block it, correctly. Note your run's start timestamp at step 0 (`date -u +%Y-%m-%dT%H:%M:%SZ`); it cannot be reconstructed at the end.
|
|
75
|
+
|
|
76
|
+
## Single source of truth
|
|
77
|
+
|
|
78
|
+
Per-REQ status, %, remarks, and bugs live in the **Requirements Status** table at the top of the one checklist (`docs/{AppName}-Checklist.md`, all REQ prefixes in a single table). Do not create separate dated result files (`docs/qa/*.md`, `docs/verify/*.md`). Smoke and verify write INTO that table. PROJECT-STATUS summarizes and points at it. The **BRD §4 Development status** table (item 9) is a *derived* feature-level rollup of those same tables — a human snapshot, never an independent source of truth; always recompute it from the checklists, never the other way round.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# _yolo-mode (shared rule — YOLO / goal mode: run unattended to completion)
|
|
2
|
+
|
|
3
|
+
## What YOLO means (owner rule 2026-08-21)
|
|
4
|
+
|
|
5
|
+
**YOLO = "I have given you all the permissions and all the access. Run until the goal is complete — not until you feel like checking in."** It exists so a whole development pass (build → verify → fix → handoff) can run on a VM with nobody watching. A 3-day run that kept stopping for a delete prompt, a git-read prompt, or a "shall I continue?" is the failure this rule removes.
|
|
6
|
+
|
|
7
|
+
YOLO is ON when **any** of these holds — you do not need the owner to say it twice:
|
|
8
|
+
|
|
9
|
+
| Trigger | How you know |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `*yolo` typed to any TechieFlow agent | you ran `bash .tfcore/utils/tf-yolo.sh on --source yolo` (do this **immediately**, first action, before anything else) |
|
|
12
|
+
| The prompt contains `YOLO` / `yolo` / `--yolo` anywhere (e.g. `*build-phase MyApp yolo`, "YOLO: finish the app") | same — run `tf-yolo.sh on` first, then the command |
|
|
13
|
+
| A Claude Code goal is active (`/goal <condition>`), or the session was started by `tf-goal.sh` | `tf-goal.sh` sets `TF_YOLO=1` + the flag for you; for a hand-typed `/goal`, run `tf-yolo.sh on --source goal` as your first action |
|
|
14
|
+
| The harness is already in a no-prompt mode (Claude Code `bypassPermissions` / `auto`, `opencode run --auto`) | the hook sees `permission_mode` itself; you should still run `tf-yolo.sh on` so the agent-side rules below apply |
|
|
15
|
+
|
|
16
|
+
`*yolo` again, or `bash .tfcore/utils/tf-yolo.sh off`, turns it off. `tf-yolo.sh status` tells you which. The flag lives at `.tfcore/.session/yolo.json` (never committed) and is read by `.tfcore/hooks/block-git.sh` (both harnesses) and `.opencode/plugin/techieflow.js`.
|
|
17
|
+
|
|
18
|
+
**The grant ends with the run — it is not a repo setting (2026-08-28).** Three things now close it, so an unnoticed flag cannot go on suppressing delete prompts for days: `tf-yolo.sh off`, **`tf-yolo.sh done`** (the sentinel below clears the flag as well as writing the outcome), and, for a session that is killed or crashes before either, an **expiry** — a flag older than 24 h (`TF_YOLO_TTL_HOURS`, `0` disables) is ignored by the hook and reported as `OFF (flag EXPIRED …)` by `status`. `tf-goal.sh` additionally clears its own flag on every exit path via an `EXIT`/`INT`/`TERM` trap, and exports `TF_YOLO=1` for the duration of the run, which is checked first and **never** expires — so a multi-day supervised run that sleeps through usage-limit windows is unaffected. If you need YOLO back, say `*yolo` again; that is one line, and it is cheaper than a repo that has been silently permissive since last week.
|
|
19
|
+
|
|
20
|
+
## What changes when YOLO is ON
|
|
21
|
+
|
|
22
|
+
**Permissions (mechanical — the hook/plugin enforce these, you just stop worrying about them):**
|
|
23
|
+
|
|
24
|
+
| Action | Normal mode | YOLO |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| `rm` / `rmdir` / `find -delete` / `sudo` | prompt (hook `ask`) | **allowed, no prompt** — delete anything the task needs (catastrophic `rm -rf /`, `~` stay denied) |
|
|
27
|
+
| Read-only git/gh — `status`, `log`, `diff`, `show`, `blame`, `grep`, `branch`, `tag -l`, `stash list`, `remote -v`, `config --get`, `gh pr list/view` | blocked | **allowed** — use it when it is genuinely the fastest evidence; the checklist table + working tree remain the primary status source |
|
|
28
|
+
| Git/gh **writes** — `commit`, `push`, `add`, `reset`, `checkout`, `switch`, `restore`, `stash`, `tag`, `merge`, `rebase`, `branch -d/-m`, `clean`, `pull`, `fetch`, `gh pr/issue create|merge|close` | blocked | **still blocked** — in every mode, forever. The owner commits. Never try a workaround. |
|
|
29
|
+
| Edits, writes, builds, test runs, booting the app, Playwright, winrun | allowed | allowed |
|
|
30
|
+
|
|
31
|
+
**Behaviour (agent-side — these are on you):**
|
|
32
|
+
|
|
33
|
+
1. **No confirmations, no elicitation, no phase-boundary pauses.** `brd_coverage_protocol`'s "pause and ask the user to CONFIRM the list" → emit the list and continue. `*run-workflow`'s "pauses for confirmation at each phase boundary" → log the boundary and continue. `elicit=true` sections → take the sensible default, mark it `<!-- yolo-default -->` / note it in the checklist Remarks, continue. "Ask once" questions (scope, AppName, which startup project, which BRD variant) → resolve from `core-config.yaml` / `PROJECT-STATUS.md` / the file system; if truly ambiguous, pick the most conservative reading and **record the decision**. The only questions that survive YOLO are the ones the owner has explicitly reserved — creating a **new test user** (`_smoke-test-policy.md`): in YOLO, use an existing documented account; if none exists, create ONE, name it `{AppName}-yolo-tester`, record it in the UsageGuide Test-users table, and move on.
|
|
34
|
+
2. **Never end a turn with a question, a plan, a menu, or "shall I…".** Ending a turn is allowed only when (a) the goal/command is complete, or (b) everything remaining is owner-only (see §Completion). Otherwise the next step is yours to take.
|
|
35
|
+
3. **Whole-checklist build passes.** `*build-phase` in YOLO (and, honestly, in every mode — build-phase §2b) means every open REQ reaches at least `Implemented` **in this pass**, the verifier is chained inline, and FIX mode loops on its `FAIL` / `Needs re-verify` rows automatically (build-phase §6c) until they pass or are genuinely `Blocked`. "Run build-phase again for the remaining REQs" is a banned ending.
|
|
36
|
+
4. **Context pressure is not a reason to stop.** If the working list is large, fan more clusters out to sub-agents (build-phase §3) and keep only the cluster table + results in your own context. Delegating is how a long run survives; stopping is not.
|
|
37
|
+
5. **Recover, don't report.** A failed build, a flaky boot, a port in use, a dead service — fix it (build ladder, verify-phase §3a escalation) and continue. Report only what you could not fix after genuinely trying.
|
|
38
|
+
6. **Still no self-attestation.** YOLO does not relax `guard-verify.sh`, `guard-status.sh`, the smoke policy, or the status gate. `Verified` still comes only from an executed verify-phase run; PROJECT-STATUS (md + html) is still the last action of every phase.
|
|
39
|
+
|
|
40
|
+
## Usage limits (5-hour / weekly) — the supervisor waits, you just resume cleanly
|
|
41
|
+
|
|
42
|
+
When the subscription limit hits mid-run the harness stops the session and prints the reset time ("resets 7pm (Asia/Kolkata)", "resets in 2h 14m", `usage limit reached|<epoch>`). Nothing inside the session can wait that out — so the wait is done **outside** it by `.tfcore/utils/tf-goal.sh`: it parses the reset time, **sleeps until reset + 15 min** (`--buffer-min`), writes `RETRY AT <time>` to `.tfcore/.session/goal.log` / `goal.json`, then **resumes the same session** (`claude -p --resume <id>` / `opencode run -c`). No reset time parseable → it **probes** instead of guessing: a one-turn `claude -p "Reply OK"` every 15 min (`--probe-min`) until the API answers cleanly, then a 15-min buffer and resume (gives up probing after `--probe-max-hours` 8 and resumes anyway). Crashes/API errors → exponential backoff (2 min → 30 min). Your only job on resume: **re-read `PROJECT-STATUS.md` + the checklist Requirements Status table and continue from the weakest open REQ** — the status gate you ran at the end of every phase is what makes the resume lossless. That is one more reason the gate is non-skippable.
|
|
43
|
+
|
|
44
|
+
If you (the agent) see a `429` / `rate_limit` / `overloaded` **tool** error from a sub-agent or an API you called, that is not the session limit: wait 60 s, retry once, then route around it (another sub-agent, smaller batch). Do not declare the goal blocked over a transient.
|
|
45
|
+
|
|
46
|
+
## Completion — the sentinel (how an unattended run knows it is over)
|
|
47
|
+
|
|
48
|
+
The supervisor stops **only** when you write the sentinel. Write it exactly once, as the very last action after the status gate + run record:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# every in-scope REQ terminal, PROJECT-STATUS.md + .html updated, runs.jsonl emitted:
|
|
52
|
+
bash .tfcore/utils/tf-yolo.sh done complete "MyApp: 23 REQs Verified, handoff written"
|
|
53
|
+
|
|
54
|
+
# everything left needs the OWNER (credentials / physical device / paid account / product decision):
|
|
55
|
+
bash .tfcore/utils/tf-yolo.sh done blocked "REQ-FN-7, REQ-NFR-2 need the production SMTP creds"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`blocked` is legitimate only when **every** remaining open REQ is owner-gated and you have finished everything else, logged each blocker under PROJECT-STATUS "Known blockers", and pointed the next command at the owner-run step. A `blocked` written because the work was long, the context was full, or you wanted a check-in is the exact failure this rule exists to stop — the supervisor will simply re-prompt you, and the log will show it.
|
|
59
|
+
|
|
60
|
+
Without a goal/supervisor (plain `*yolo` in an interactive session) the sentinel is harmless; still write it — it records the outcome for `tf-yolo.sh status` **and it is what turns YOLO back off**. An interactive `*yolo` that ends without it leaves the repo permissive until the 24 h expiry catches it.
|
|
61
|
+
|
|
62
|
+
## Starting an unattended run (owner side — the VM recipe)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Claude Code (default). Runs in .tfcore/.session/goal.log; resumes across limit windows.
|
|
66
|
+
bash .tfcore/utils/tf-goal.sh /path/to/App "Take MyApp from its current PROJECT-STATUS to Handoff: build every open REQ, verify all, fix until every row is Verified, then *handoff-phase."
|
|
67
|
+
|
|
68
|
+
# OpenCode
|
|
69
|
+
bash .tfcore/utils/tf-goal.sh --harness opencode --model opencode-go/kimi-k3 /path/to/App @goal.md
|
|
70
|
+
|
|
71
|
+
# after a reboot / to pick up where it left off
|
|
72
|
+
bash .tfcore/utils/tf-goal.sh --resume /path/to/App
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Interactive alternative: start Claude Code with `--permission-mode bypassPermissions` (or `auto`), type `/goal <condition>`, then `/TechieFlow:agents:flow-master *yolo` and the command. That gives you YOLO permissions and the goal loop, but **not** the limit-wait — for that, use `tf-goal.sh`.
|
|
76
|
+
|
|
77
|
+
Exit codes: `0` complete · `3` blocked (owner input needed — read `goal-done.json`) · `4` max cycles.
|