@techierathore/techieflow 1.0.2 → 1.0.3
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 +0 -5
- package/.claude/commands/TechieFlow/agents/architect.md +0 -6
- package/.claude/commands/TechieFlow/agents/flow-master.md +41 -215
- package/.claude/commands/TechieFlow/agents/verifier.md +23 -64
- package/.claude/commands/TechieFlow/tasks/_metrics-emit-gate.md +24 -117
- package/.claude/commands/TechieFlow/tasks/_smoke-test-policy.md +20 -84
- package/.claude/commands/TechieFlow/tasks/_status-update-gate.md +10 -74
- package/.claude/commands/TechieFlow/tasks/_yolo-mode.md +20 -58
- package/.claude/commands/TechieFlow/tasks/amend-docs.md +20 -143
- package/.claude/commands/TechieFlow/tasks/build-phase.md +14 -224
- package/.claude/commands/TechieFlow/tasks/day1-brownfield.md +31 -505
- package/.claude/commands/TechieFlow/tasks/day1-greenfield.md +28 -213
- package/.claude/commands/TechieFlow/tasks/deploy-checklist.md +19 -0
- package/.claude/commands/TechieFlow/tasks/devguide.md +10 -219
- package/.claude/commands/TechieFlow/tasks/fix-issues.md +10 -129
- package/.claude/commands/TechieFlow/tasks/log-miss.md +19 -158
- package/.claude/commands/TechieFlow/tasks/metrics-report.md +1 -1
- package/.claude/commands/TechieFlow/tasks/mockups.md +12 -117
- package/.claude/commands/TechieFlow/tasks/refresh-status.md +9 -130
- package/.claude/commands/TechieFlow/tasks/split-brd.md +10 -126
- package/.claude/commands/TechieFlow/tasks/triage-and-fix.md +14 -0
- package/.claude/commands/TechieFlow/tasks/triage-issues.md +11 -152
- package/.claude/commands/TechieFlow/tasks/verify-phase.md +36 -572
- package/.opencode/plugin/techieflow.js +39 -12
- package/.tfcore/agents/analyst.md +0 -5
- package/.tfcore/agents/architect.md +0 -6
- package/.tfcore/agents/flow-master.md +41 -215
- package/.tfcore/agents/verifier.md +23 -64
- package/.tfcore/core-config.yaml +10 -0
- package/.tfcore/hooks/block-git.sh +4 -4
- package/.tfcore/hooks/guard-artifacts.sh +2 -2
- package/.tfcore/hooks/guard-build.sh +76 -0
- package/.tfcore/hooks/guard-db.sh +90 -0
- package/.tfcore/hooks/guard-metrics.sh +56 -0
- package/.tfcore/hooks/guard-status-html.sh +116 -71
- package/.tfcore/hooks/guard-status.sh +43 -16
- package/.tfcore/hooks/guard-verify.sh +70 -48
- package/.tfcore/hooks/sweep-artifacts.sh +2 -2
- package/.tfcore/install-manifest.yaml +0 -18
- package/.tfcore/routing.yaml +25 -14
- package/.tfcore/standards/coding-standards-core.md +61 -0
- package/.tfcore/standards/coding-standards-dotnet.md +93 -0
- package/.tfcore/tasks/_metrics-emit-gate.md +24 -117
- package/.tfcore/tasks/_smoke-test-policy.md +20 -84
- package/.tfcore/tasks/_status-update-gate.md +10 -74
- package/.tfcore/tasks/_yolo-mode.md +20 -58
- package/.tfcore/tasks/amend-docs.md +20 -143
- package/.tfcore/tasks/build-phase.md +14 -224
- package/.tfcore/tasks/day1-brownfield.md +31 -505
- package/.tfcore/tasks/day1-greenfield.md +28 -213
- package/.tfcore/tasks/deploy-checklist.md +19 -0
- package/.tfcore/tasks/devguide.md +10 -219
- package/.tfcore/tasks/fix-issues.md +10 -129
- package/.tfcore/tasks/log-miss.md +19 -158
- package/.tfcore/tasks/metrics-report.md +1 -1
- package/.tfcore/tasks/mockups.md +12 -117
- package/.tfcore/tasks/refresh-status.md +9 -130
- package/.tfcore/tasks/split-brd.md +10 -126
- package/.tfcore/tasks/triage-and-fix.md +14 -0
- package/.tfcore/tasks/triage-issues.md +11 -152
- package/.tfcore/tasks/verify-phase.md +36 -572
- package/.tfcore/telemetry/SCHEMA.md +43 -7
- package/.tfcore/telemetry/tf-metrics.sh +152 -17
- package/.tfcore/templates/project-brief-tmpl.yaml +1 -1
- package/.tfcore/templates/stack-defaults/dotnet.md +35 -0
- package/.tfcore/templates/stack-questions.md +77 -0
- package/.tfcore/templates/v4custom/app-agents-md-tmpl.md +3 -4
- package/.tfcore/templates/v4custom/app-architecture-tmpl.md +107 -115
- package/.tfcore/templates/v4custom/app-brd-tmpl.md +108 -184
- package/.tfcore/templates/v4custom/app-checklist-tmpl.md +48 -73
- package/.tfcore/templates/v4custom/app-claude-md-tmpl.md +1 -1
- package/.tfcore/templates/v4custom/app-coding-standards-tmpl.md +52 -0
- package/.tfcore/templates/v4custom/app-deployment-checklist-tmpl.md +86 -0
- package/.tfcore/templates/v4custom/app-devguide-tmpl.md +69 -146
- package/.tfcore/templates/v4custom/app-phases-tmpl.md +35 -0
- package/.tfcore/templates/v4custom/app-productguide-tmpl.md +38 -35
- package/.tfcore/templates/v4custom/app-project-status-tmpl.md +63 -73
- package/.tfcore/templates/v4custom/app-uidesign-tmpl.md +62 -37
- package/.tfcore/templates/v4custom/app-usageguide-tmpl.md +69 -54
- package/.tfcore/templates/v4custom/build-invocation-ladder.md +17 -180
- package/.tfcore/templates/v4custom/build-subagent-prompt.md +17 -0
- package/.tfcore/templates/v4custom/metrics-report-template.md +2 -2
- package/.tfcore/user-guide.md +0 -23
- package/.tfcore/utils/__pycache__/tf-brd-status.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-checklist-edit.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-codex-bind.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-codex-telemetry.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-day1-files.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-devguide-list.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-doc-check.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-log-miss.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-misses-md.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-mockups-locate.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-opencode-audit.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-perf-grade.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-render-html.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-split-brd.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-status-facts.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-triage.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-verify-list.cpython-312.pyc +0 -0
- package/.tfcore/utils/__pycache__/tf-verify-verdict.cpython-312.pyc +0 -0
- package/.tfcore/utils/tf-brd-status.py +176 -0
- package/.tfcore/utils/tf-brd-status.sh +19 -0
- package/.tfcore/utils/tf-build-list.py +191 -0
- package/.tfcore/utils/tf-build-list.sh +20 -0
- package/.tfcore/utils/tf-build.sh +143 -0
- package/.tfcore/utils/tf-cdp-relay.ps1 +64 -0
- package/.tfcore/utils/tf-checklist-edit.py +133 -0
- package/.tfcore/utils/tf-day1-files.py +208 -0
- package/.tfcore/utils/tf-day1-files.sh +20 -0
- package/.tfcore/utils/tf-devguide-list.py +249 -0
- package/.tfcore/utils/tf-devguide-list.sh +18 -0
- package/.tfcore/utils/tf-doc-check.py +1267 -0
- package/.tfcore/utils/tf-doc-check.sh +29 -0
- package/.tfcore/utils/tf-emit.sh +203 -13
- package/.tfcore/utils/tf-fix-close.sh +83 -0
- package/.tfcore/utils/tf-goal.sh +193 -62
- package/.tfcore/utils/tf-harness.sh +4 -9
- package/.tfcore/utils/tf-log-miss.py +197 -0
- package/.tfcore/utils/tf-log-miss.sh +14 -0
- package/.tfcore/utils/tf-misses-md.py +211 -0
- package/.tfcore/utils/tf-misses-md.sh +13 -0
- package/.tfcore/utils/tf-mockups-locate.py +66 -0
- package/.tfcore/utils/tf-mockups-locate.sh +18 -0
- package/.tfcore/utils/tf-opencode-audit.py +23 -7
- package/.tfcore/utils/tf-perf-grade.py +97 -0
- package/.tfcore/utils/tf-perf-grade.sh +12 -0
- package/.tfcore/utils/tf-phase.sh +74 -0
- package/.tfcore/utils/tf-routing-bind.sh +10 -5
- package/.tfcore/utils/tf-routing.sh +6 -7
- package/.tfcore/utils/tf-split-brd.py +304 -0
- package/.tfcore/utils/tf-split-brd.sh +22 -0
- package/.tfcore/utils/tf-status-evidence.sh +68 -0
- package/.tfcore/utils/tf-status-facts.py +309 -0
- package/.tfcore/utils/tf-status-facts.sh +20 -0
- package/.tfcore/utils/tf-triage.py +243 -0
- package/.tfcore/utils/tf-triage.sh +16 -0
- package/.tfcore/utils/tf-verify-boot.sh +250 -0
- package/.tfcore/utils/tf-verify-emit.sh +110 -0
- package/.tfcore/utils/tf-verify-env.sh +88 -0
- package/.tfcore/utils/tf-verify-list.py +270 -0
- package/.tfcore/utils/tf-verify-list.sh +13 -0
- package/.tfcore/utils/tf-verify-screens.mjs +283 -0
- package/.tfcore/utils/tf-verify-screens.sh +22 -0
- package/.tfcore/utils/tf-verify-tests.sh +123 -0
- package/.tfcore/utils/tf-verify-verdict.py +283 -0
- package/.tfcore/utils/tf-verify-verdict.sh +15 -0
- package/.tfcore/utils/tf-yolo.sh +59 -0
- package/README.md +114 -1149
- package/docs/TechieFlow-Installation.md +1 -5
- package/opencode.jsonc +13 -33
- package/package.json +1 -5
- package/scripts/install.mjs +52 -46
- package/.claude/commands/TechieFlow/tasks/advanced-elicitation.md +0 -117
- package/.claude/commands/TechieFlow/tasks/author-brd.md +0 -79
- package/.claude/commands/TechieFlow/tasks/document-project.md +0 -343
- package/.claude/commands/TechieFlow/tasks/execute-checklist.md +0 -86
- package/.claude/commands/TechieFlow/tasks/index-docs.md +0 -173
- package/.claude/commands/TechieFlow/tasks/kb-mode-interaction.md +0 -75
- package/.claude/commands/TechieFlow/tasks/shard-doc.md +0 -185
- package/.codex/config.toml +0 -46
- package/.codex/hooks.json +0 -63
- package/.codex/rules/techieflow.rules +0 -8
- package/.tfcore/hooks/codex-adapter.py +0 -248
- package/.tfcore/tasks/advanced-elicitation.md +0 -117
- package/.tfcore/tasks/author-brd.md +0 -79
- package/.tfcore/tasks/document-project.md +0 -343
- package/.tfcore/tasks/execute-checklist.md +0 -86
- package/.tfcore/tasks/index-docs.md +0 -173
- package/.tfcore/tasks/kb-mode-interaction.md +0 -75
- package/.tfcore/tasks/shard-doc.md +0 -185
- package/.tfcore/utils/tf-codex-bind.py +0 -196
- package/.tfcore/utils/tf-codex-telemetry.py +0 -60
- package/WORKFLOW.html +0 -1986
|
@@ -1,27 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# TechieFlow PreToolUse hook —
|
|
2
|
+
# TechieFlow PreToolUse hook — a `Verified` cell is written only by an executed verify run.
|
|
3
3
|
#
|
|
4
|
-
# `Verified` is the verifier's verdict
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
4
|
+
# `Verified` is the verifier's verdict. Since Sitting 4c (2026-09-06) the verify run's own script,
|
|
5
|
+
# tf-verify-verdict.sh, writes the cells from the evidence it collected and writes the ledger
|
|
6
|
+
# docs/.last-verify.json with every row's verdict. This hook refuses any Write/Edit/MultiEdit of a
|
|
7
|
+
# *-Checklist.md that INTRODUCES a `Verified` cell unless a ledger dated today lists that row as
|
|
8
|
+
# PASS. Owner decision 2026-09-06: a hand-written Verified the ledger does not list is refused.
|
|
9
|
+
# Two older ledger shapes still unlock: {"mode":"reconcile"} written by *refresh-status for a row
|
|
10
|
+
# whose Remarks already carry dated evidence, and a same-day ledger without a `rows` map from a
|
|
11
|
+
# framework version before this sitting (the row is then checked by date only, as before).
|
|
10
12
|
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
# records verdicts — after actually booting the app and running the gates.
|
|
14
|
-
# Any Write/Edit/MultiEdit to a `*-Checklist.md` that INTRODUCES a `Verified`
|
|
15
|
-
# status cell is blocked unless a same-day ledger sits next to the checklist.
|
|
16
|
-
#
|
|
17
|
-
# Wired in .claude/settings.json → hooks.PreToolUse (matcher "Write|Edit|MultiEdit").
|
|
18
|
-
# Exit 2 + stderr = block the call and feed the message back to the agent.
|
|
13
|
+
# Wired in .claude/settings.json → hooks.PreToolUse (matcher "Write|Edit|MultiEdit") and in the
|
|
14
|
+
# OpenCode plugin. Exit 2 + stderr = block the call and feed the message back to the agent.
|
|
19
15
|
# Fails OPEN (exit 0) if python3 or parseable JSON is unavailable.
|
|
20
16
|
|
|
21
17
|
INPUT="$(cat)"
|
|
22
18
|
command -v python3 >/dev/null 2>&1 || exit 0
|
|
23
19
|
|
|
24
|
-
# stdin feeds python the SCRIPT (heredoc), so the payload travels via env var.
|
|
25
20
|
TF_HOOK_INPUT="$INPUT" python3 - <<'PY'
|
|
26
21
|
import datetime, json, os, re, sys
|
|
27
22
|
|
|
@@ -35,10 +30,19 @@ path = (ti.get("file_path") or "").replace("\\", "/")
|
|
|
35
30
|
if not path.rsplit("/", 1)[-1].lower().endswith("-checklist.md"):
|
|
36
31
|
sys.exit(0)
|
|
37
32
|
|
|
38
|
-
# A `Verified` STATUS CELL: a table cell holding exactly Verified (optional
|
|
39
|
-
# bold / trailing date qualifier). Remarks prose like "VERIFIED 2026-07-07"
|
|
40
|
-
# or "Needs re-verify" does not match.
|
|
41
33
|
CELL = re.compile(r"\|\s*\**Verified\**\s*(?:\([^)|]*\))?\s*\|")
|
|
34
|
+
ROW = re.compile(r"^\s*\|\s*`?(REQ-[A-Z]+-\d+)`?\s*\|", re.I)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def verified_ids(text):
|
|
38
|
+
"""the row ids whose STATUS cell reads Verified, in a piece of checklist text"""
|
|
39
|
+
out = set()
|
|
40
|
+
for line in text.splitlines():
|
|
41
|
+
m = ROW.match(line)
|
|
42
|
+
if m and CELL.search(line):
|
|
43
|
+
out.add(m.group(1).upper())
|
|
44
|
+
return out
|
|
45
|
+
|
|
42
46
|
|
|
43
47
|
new_pieces, old_pieces = [], []
|
|
44
48
|
if isinstance(ti.get("content"), str):
|
|
@@ -56,51 +60,69 @@ for e in ti.get("edits") or []:
|
|
|
56
60
|
|
|
57
61
|
n_new = sum(len(CELL.findall(p)) for p in new_pieces)
|
|
58
62
|
n_old = sum(len(CELL.findall(p)) for p in old_pieces)
|
|
63
|
+
if isinstance(ti.get("content"), str):
|
|
64
|
+
# a whole-file write: what is Verified on disk already does not count as new
|
|
65
|
+
try:
|
|
66
|
+
with open(path, encoding="utf-8", errors="replace") as f:
|
|
67
|
+
n_old = len(CELL.findall(f.read()))
|
|
68
|
+
except FileNotFoundError:
|
|
69
|
+
n_old = 0
|
|
59
70
|
if n_new <= n_old:
|
|
60
|
-
sys.exit(0) # no NEW Verified cell
|
|
71
|
+
sys.exit(0) # no NEW Verified cell (a demotion, a move, another edit)
|
|
72
|
+
|
|
73
|
+
new_ids = set().union(*(verified_ids(p) for p in new_pieces)) if new_pieces else set()
|
|
74
|
+
old_ids = set().union(*(verified_ids(p) for p in old_pieces)) if old_pieces else set()
|
|
75
|
+
if isinstance(ti.get("content"), str):
|
|
76
|
+
try:
|
|
77
|
+
with open(path, encoding="utf-8", errors="replace") as f:
|
|
78
|
+
old_ids = verified_ids(f.read())
|
|
79
|
+
except FileNotFoundError:
|
|
80
|
+
old_ids = set()
|
|
81
|
+
introduced = new_ids - old_ids
|
|
61
82
|
|
|
62
|
-
|
|
63
|
-
|
|
83
|
+
ledger_path = os.path.join(os.path.dirname(path) or ".", ".last-verify.json")
|
|
84
|
+
today = datetime.date.today().isoformat()
|
|
64
85
|
try:
|
|
65
86
|
with open(ledger_path, "r", encoding="utf-8") as f:
|
|
66
87
|
ledger = json.load(f)
|
|
67
|
-
if str(ledger.get("date", "")).strip() == datetime.date.today().isoformat():
|
|
68
|
-
sys.exit(0) # fresh ledger — an executed verify-phase (or documented reconcile) unlocked it
|
|
69
|
-
stale = f"exists but is dated {ledger.get('date')!r}, not today"
|
|
70
88
|
except FileNotFoundError:
|
|
71
|
-
|
|
89
|
+
ledger, problem = None, "does not exist"
|
|
72
90
|
except Exception:
|
|
73
|
-
|
|
91
|
+
ledger, problem = None, "exists but is not valid JSON"
|
|
92
|
+
|
|
93
|
+
if ledger is not None:
|
|
94
|
+
if str(ledger.get("date", "")).strip() != today:
|
|
95
|
+
problem = f"exists but is dated {ledger.get('date')!r}, not today"
|
|
96
|
+
elif ledger.get("mode") == "reconcile":
|
|
97
|
+
sys.exit(0) # *refresh-status reconciling a row to dated evidence already in its Remarks
|
|
98
|
+
elif "rows" not in ledger:
|
|
99
|
+
sys.exit(0) # a same-day ledger from a framework version before Sitting 4c: date unlocks
|
|
100
|
+
else:
|
|
101
|
+
rows = ledger.get("rows") or {}
|
|
102
|
+
not_listed = sorted(i for i in introduced if rows.get(i) != "PASS")
|
|
103
|
+
if not introduced:
|
|
104
|
+
# a Verified cell without a readable row id (a malformed line): refuse, nothing can vouch for it
|
|
105
|
+
not_listed = ["(row id not readable)"]
|
|
106
|
+
if not not_listed:
|
|
107
|
+
sys.exit(0)
|
|
108
|
+
problem = ("lists these rows as " + ", ".join(f"{i}: {rows.get(i, 'absent')}" for i in not_listed)
|
|
109
|
+
+ ", not PASS")
|
|
74
110
|
|
|
75
111
|
print(
|
|
76
112
|
"BLOCKED by TechieFlow policy: this write INTRODUCES a `Verified` status, "
|
|
77
|
-
f"but the verify
|
|
78
|
-
file=sys.stderr,
|
|
79
|
-
)
|
|
80
|
-
print(
|
|
81
|
-
" - `Verified` is the VERIFIER'S verdict. It is written only downstream of an "
|
|
82
|
-
"EXECUTED .tfcore/tasks/verify-phase.md run — boot the app, run the scoped "
|
|
83
|
-
"tests, apply the §4a data-render + §4b visual-truth gates, write the run "
|
|
84
|
-
"ledger (verify-phase §6), THEN record verdicts.",
|
|
85
|
-
file=sys.stderr,
|
|
86
|
-
)
|
|
87
|
-
print(
|
|
88
|
-
" - If you are the build orchestrator after your self-smoke: your ceiling is "
|
|
89
|
-
"`Implemented` (build-phase §6a / _smoke-test-policy). Chain the verifier by "
|
|
90
|
-
"EXECUTING verify-phase inline (build-phase §6b) — summarizing your smoke as "
|
|
91
|
-
"a verdict is self-attestation, the exact failure this hook exists to stop.",
|
|
113
|
+
f"but the verify ledger {ledger_path} {problem}.",
|
|
92
114
|
file=sys.stderr,
|
|
93
115
|
)
|
|
94
116
|
print(
|
|
95
|
-
" -
|
|
96
|
-
"
|
|
97
|
-
|
|
98
|
-
'date>"} first (refresh-status §4).',
|
|
117
|
+
" - `Verified` is written by the verify run's own script from the evidence it collected: "
|
|
118
|
+
"bash .tfcore/utils/tf-verify-verdict.sh <App> --apply, after boot, tests, screens, assets, "
|
|
119
|
+
"parity and perf have run (.tfcore/tasks/verify-phase.md). Writing it by hand is refused.",
|
|
99
120
|
file=sys.stderr,
|
|
100
121
|
)
|
|
101
122
|
print(
|
|
102
|
-
" -
|
|
103
|
-
"
|
|
123
|
+
" - A build, a fix or a smoke reaches at most `Implemented`; chain the verifier by executing "
|
|
124
|
+
"verify-phase.md. *refresh-status may reconcile a row that already carries dated verify evidence "
|
|
125
|
+
'by writing the ledger {"date":"<today>","mode":"reconcile","evidence":"<that date>"} first.',
|
|
104
126
|
file=sys.stderr,
|
|
105
127
|
)
|
|
106
128
|
sys.exit(2)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# TechieFlow hook — automatic sweep of expired run material (added 2026-08-26).
|
|
3
3
|
#
|
|
4
4
|
# Wired as a SessionStart hook in .claude/settings.json (Claude Code), as
|
|
5
|
-
#
|
|
5
|
+
# on the first root
|
|
6
6
|
# `session.created` in .opencode/plugin/techieflow.js (OpenCode).
|
|
7
7
|
#
|
|
8
8
|
# WHY: verify-phase.md §1 pins every run artifact under tests/.artifacts/ and
|
|
@@ -60,7 +60,7 @@ root = os.path.realpath(root)
|
|
|
60
60
|
DRY = os.environ.get("TF_SWEEP_DRY_RUN") == "1"
|
|
61
61
|
|
|
62
62
|
# Throttle: at most one sweep per hour per project, whichever harness fires it
|
|
63
|
-
# (
|
|
63
|
+
# (a harness may re-fire session-start on every prompt; a walk of a big tree on every
|
|
64
64
|
# turn is waste). TF_SWEEP_FORCE=1 bypasses. Dry runs never touch the stamp.
|
|
65
65
|
stamp = os.path.join(root, ".tfcore", ".session", "sweep.stamp")
|
|
66
66
|
if not DRY and os.environ.get("TF_SWEEP_FORCE") != "1":
|
|
@@ -91,9 +91,6 @@ files:
|
|
|
91
91
|
- path: .tfcore\tasks\test-design.md
|
|
92
92
|
hash: bcd13a95d296ce22
|
|
93
93
|
modified: false
|
|
94
|
-
- path: .tfcore\tasks\shard-doc.md
|
|
95
|
-
hash: a83c900f64ea3d4f
|
|
96
|
-
modified: false
|
|
97
94
|
- path: .tfcore\tasks\risk-profile.md
|
|
98
95
|
hash: addf5d143cfe6f12
|
|
99
96
|
modified: false
|
|
@@ -106,24 +103,12 @@ files:
|
|
|
106
103
|
- path: .tfcore\tasks\nfr-assess.md
|
|
107
104
|
hash: b9011d038b81a69b
|
|
108
105
|
modified: false
|
|
109
|
-
- path: .tfcore\tasks\kb-mode-interaction.md
|
|
110
|
-
hash: 4d6b921c24ba4999
|
|
111
|
-
modified: false
|
|
112
|
-
- path: .tfcore\tasks\index-docs.md
|
|
113
|
-
hash: 70b1d526b19d015e
|
|
114
|
-
modified: false
|
|
115
106
|
- path: .tfcore\tasks\generate-ai-frontend-prompt.md
|
|
116
107
|
hash: ca4cabd824ea1b60
|
|
117
108
|
modified: false
|
|
118
109
|
- path: .tfcore\tasks\facilitate-brainstorming-session.md
|
|
119
110
|
hash: 38594d876614e077
|
|
120
111
|
modified: false
|
|
121
|
-
- path: .tfcore\tasks\execute-checklist.md
|
|
122
|
-
hash: 8a704b6f2bc52e12
|
|
123
|
-
modified: false
|
|
124
|
-
- path: .tfcore\tasks\document-project.md
|
|
125
|
-
hash: 98f8790d20e83cf3
|
|
126
|
-
modified: false
|
|
127
112
|
- path: .tfcore\tasks\create-next-story.md
|
|
128
113
|
hash: 99e5cc3237a9cffd
|
|
129
114
|
modified: false
|
|
@@ -148,9 +133,6 @@ files:
|
|
|
148
133
|
- path: .tfcore\tasks\apply-qa-fixes.md
|
|
149
134
|
hash: 70e6143a80f7296b
|
|
150
135
|
modified: false
|
|
151
|
-
- path: .tfcore\tasks\advanced-elicitation.md
|
|
152
|
-
hash: d39118bf32237a21
|
|
153
|
-
modified: false
|
|
154
136
|
- path: .tfcore\data\test-priorities-matrix.md
|
|
155
137
|
hash: 1dd5698a46ab054e
|
|
156
138
|
modified: false
|
package/.tfcore/routing.yaml
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# A phase declares a TIER, never a model. The tiers map resolves a tier to a
|
|
8
8
|
# per-harness model id (Claude Code aliases: opus|sonnet|haiku|inherit|<id>,
|
|
9
9
|
# pinnable via ANTHROPIC_DEFAULT_*_MODEL; OpenCode ids: provider/model, list
|
|
10
|
-
# with `opencode models
|
|
10
|
+
# with `opencode models`).
|
|
11
11
|
# Routing is declared at the harness boundary and
|
|
12
12
|
# OBSERVED by telemetry (runs.jsonl model/tier fields) — it is never enforced
|
|
13
13
|
# mid-turn, because neither harness can switch a running turn's model.
|
|
@@ -23,26 +23,36 @@
|
|
|
23
23
|
# §5.3/§5.4 and the rollout order in §6. Flipping the flag alone changes
|
|
24
24
|
# nothing; that is deliberate.
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
# Owner decisions: 2026-09-05, Sonnet for every long-running Claude phase, Haiku for the cheap ones;
|
|
27
|
+
# 2026-09-06, the OpenAI models for OpenCode (gpt-5.6-terra for frontier and standard, gpt-5.6-luna
|
|
28
|
+
# for economy) after the OpenCode Go monthly limit was reached with MiMo.
|
|
29
|
+
#
|
|
30
|
+
# HOW TO CHANGE A MODEL (the plain version; the full guide is docs/TechieFlow-Routing-Guide.md):
|
|
31
|
+
# 1. This file is the FRAMEWORK DEFAULT. A project gets a copy at .tfcore/routing.yaml when it is
|
|
32
|
+
# scaffolded, and update-framework.sh never overwrites that copy. So to change one project,
|
|
33
|
+
# edit the project's copy; to change every future project, edit this one.
|
|
34
|
+
# 2. Edit the model id under `tiers:` for the harness you use (claude: opus|sonnet|haiku or a
|
|
35
|
+
# full id; opencode: provider/model as printed by `opencode models`).
|
|
36
|
+
# 3. In the project folder run: bash .tfcore/utils/tf-routing-bind.sh
|
|
37
|
+
# That regenerates the harness bindings (.claude/agents/*.md, .claude/commands/tf/*.md,
|
|
38
|
+
# .opencode/opencode.json). Nothing changes until it runs.
|
|
39
|
+
# 4. For one unattended run only, pass --model <id> to tf-goal.sh instead; the main agent uses
|
|
40
|
+
# it, the sub-agents still use the bindings from step 3.
|
|
41
|
+
enabled: true
|
|
28
42
|
# ---------------------------------------------------------------------------
|
|
29
43
|
# Tier → model id, per harness. STARTING VALUES — the owner tunes these.
|
|
30
|
-
# OpenCode ids
|
|
31
|
-
# Zen gateway); swap for anthropic/* ids if an Anthropic key is configured.
|
|
44
|
+
# OpenCode ids are provider/model as printed by `opencode models` on this machine.
|
|
32
45
|
# ---------------------------------------------------------------------------
|
|
33
46
|
tiers:
|
|
34
47
|
frontier:
|
|
35
|
-
claude:
|
|
36
|
-
opencode:
|
|
37
|
-
codex: gpt-5.6
|
|
48
|
+
claude: sonnet
|
|
49
|
+
opencode: openai/gpt-5.6-terra
|
|
38
50
|
standard:
|
|
39
51
|
claude: sonnet
|
|
40
|
-
opencode:
|
|
41
|
-
codex: gpt-5.6-terra
|
|
52
|
+
opencode: openai/gpt-5.6-terra
|
|
42
53
|
economy:
|
|
43
54
|
claude: haiku
|
|
44
|
-
opencode:
|
|
45
|
-
codex: gpt-5.6-luna
|
|
55
|
+
opencode: openai/gpt-5.6-luna
|
|
46
56
|
|
|
47
57
|
# ---------------------------------------------------------------------------
|
|
48
58
|
# Phase → tier. One line each; values: frontier | standard | economy | inherit.
|
|
@@ -52,13 +62,14 @@ tiers:
|
|
|
52
62
|
phases:
|
|
53
63
|
day1-greenfield: frontier
|
|
54
64
|
day1-brownfield: frontier
|
|
55
|
-
author-brd: frontier
|
|
56
65
|
amend-docs: frontier
|
|
57
66
|
mockups: standard
|
|
58
67
|
split-brd: standard
|
|
59
68
|
build-phase: standard
|
|
60
69
|
fix-issues: frontier
|
|
70
|
+
triage-and-fix: frontier
|
|
61
71
|
triage-issues: standard
|
|
72
|
+
log-miss: economy
|
|
62
73
|
verify-phase: standard
|
|
63
74
|
devguide: standard
|
|
64
75
|
productguide: economy
|
|
@@ -79,7 +90,7 @@ subagents:
|
|
|
79
90
|
tf-explorer: economy
|
|
80
91
|
|
|
81
92
|
# ---------------------------------------------------------------------------
|
|
82
|
-
# Tier → reasoning effort (used by Claude Code
|
|
93
|
+
# Tier → reasoning effort (used by Claude Code; ignored by OpenCode).
|
|
83
94
|
# ---------------------------------------------------------------------------
|
|
84
95
|
effort:
|
|
85
96
|
frontier: high
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# TechieFlow — Coding Standards, core
|
|
2
|
+
|
|
3
|
+
<!-- How this file is used and edited.
|
|
4
|
+
Applies to EVERY project, whatever the stack. It is loaded by the build and by the verifier's
|
|
5
|
+
standards check together with the stack file named in the project's Coding Standards document
|
|
6
|
+
(docs/<App>-Coding-Standards.md → "Standards applied"). Rules here are technology-neutral;
|
|
7
|
+
anything that names a language, framework or package belongs in a stack file
|
|
8
|
+
(.tfcore/standards/coding-standards-<stack>.md).
|
|
9
|
+
To change a rule: edit this file in the TechieFlow repository, then run update-framework.sh on
|
|
10
|
+
each project. Projects never edit their .tfcore/ copy. A rule an agent has ignored twice becomes
|
|
11
|
+
a script or a hook, or is deleted; it never gets a second paragraph. -->
|
|
12
|
+
|
|
13
|
+
## 1. Names
|
|
14
|
+
|
|
15
|
+
- One naming style per kind of thing, declared in the stack file, used everywhere. Never mix styles in one project.
|
|
16
|
+
- Names say what a thing is or does. No abbreviations a newcomer would have to ask about.
|
|
17
|
+
- Files are named after the one type they hold.
|
|
18
|
+
|
|
19
|
+
## 2. Layout
|
|
20
|
+
|
|
21
|
+
- Source under `src/`, tests under `tests/`. No other folders at the repository root unless the stack file allows one.
|
|
22
|
+
- Log files go under the build output folder, never at the repository root.
|
|
23
|
+
- The primary executable project carries the product name. A project named `<App>.App` is not allowed.
|
|
24
|
+
|
|
25
|
+
## 3. Dependencies and configuration
|
|
26
|
+
|
|
27
|
+
- No package is added without a row in the Architecture Decisions log saying why.
|
|
28
|
+
- One configuration mechanism per project. A second one is a defect.
|
|
29
|
+
- A missing feature in an internal library (TrBlazeUI, TechieRag, TechieFlow) is recorded in that library's feedback file and the feature is held. No workaround is written.
|
|
30
|
+
|
|
31
|
+
## 4. Code shape
|
|
32
|
+
|
|
33
|
+
- One type per file. Small methods. Early returns for validation. At most three levels of nesting.
|
|
34
|
+
- Every public member has a documentation comment in the language's own form.
|
|
35
|
+
- No commented-out code. Comments say why, not what.
|
|
36
|
+
|
|
37
|
+
## 5. Tests
|
|
38
|
+
|
|
39
|
+
- A test project exists from day one.
|
|
40
|
+
- Test names are short; the scenario lives in the test's documentation comment.
|
|
41
|
+
- Arrange, act, assert. One behaviour per test.
|
|
42
|
+
|
|
43
|
+
## 6. Security
|
|
44
|
+
|
|
45
|
+
- No credentials in code or in committed configuration. Secrets come from the mechanism in Stack Q2.
|
|
46
|
+
- Database access uses parameters, never string-built queries.
|
|
47
|
+
- Every input from outside the process is validated at the boundary. Security events are logged.
|
|
48
|
+
|
|
49
|
+
## 7. Logging
|
|
50
|
+
|
|
51
|
+
- Every executable head writes a rolling log file, wired at startup before anything else can fail, and logs unhandled exceptions at its boundary.
|
|
52
|
+
- Libraries log through the logging abstraction only; they never reference a logging implementation.
|
|
53
|
+
|
|
54
|
+
## 8. Testability
|
|
55
|
+
|
|
56
|
+
- Every interactive or data-bound control the verifier must reach carries a stable test id, named by intent (`LoginSubmit`, `EntriesGrid`), never by position.
|
|
57
|
+
|
|
58
|
+
## 9. Enforcement
|
|
59
|
+
|
|
60
|
+
- The machine-checkable subset lives in the repository's editor configuration and analyzer settings, as the stack file specifies.
|
|
61
|
+
- The verifier's standards check runs the greps listed in the stack file's Enforcement section and records findings in the checklist Remarks and PROJECT-STATUS.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# TechieFlow — Coding Standards, .NET
|
|
2
|
+
|
|
3
|
+
<!-- How this file is used and edited.
|
|
4
|
+
The .NET answer set's coding standards. Loaded with coding-standards-core.md when a project's
|
|
5
|
+
Coding Standards document names it. Owners in another stack write their own
|
|
6
|
+
coding-standards-<stack>.md with the same section names.
|
|
7
|
+
Seeded from the framework author's projects (the two sample files in the TechieFlow docs folder).
|
|
8
|
+
To change a rule: edit this file in the TechieFlow repository, then run update-framework.sh on
|
|
9
|
+
each project. Per-project choices this file leaves open are recorded in
|
|
10
|
+
docs/<App>-Coding-Standards.md → "Standards applied"; project-only rules go in "Project rules". -->
|
|
11
|
+
|
|
12
|
+
## 1. Names
|
|
13
|
+
|
|
14
|
+
**Never use underscores** in any identifier, database object or environment variable name.
|
|
15
|
+
|
|
16
|
+
| Kind | Convention | Example |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Classes, records, structs | PascalCase, descriptive | `SqlQueryBuilder`, not `SqlQB` |
|
|
19
|
+
| Interfaces | `I` prefix | `IQueryExecutor` |
|
|
20
|
+
| Methods | PascalCase verb phrase; async methods end in `Async` | `GetConnectionAsync()` |
|
|
21
|
+
| Properties | PascalCase, no prefix | `ConnectionString` |
|
|
22
|
+
| Instance fields | **per-project choice**: `obj` prefix (`objLogger`) or bare PascalCase (`Logger`). Default `obj`. Recorded in the project's Coding Standards | `private readonly ILogger<X> objLogger;` |
|
|
23
|
+
| Static and const fields | PascalCase, no prefix | `MaxRetryCount`, not `MAX_RETRY_COUNT` |
|
|
24
|
+
| Method parameters | `a` prefix + PascalCase | `LoginAsync(string aEmail)` |
|
|
25
|
+
| Local variables | `v` prefix + PascalCase | `var vResponse = …` |
|
|
26
|
+
| Booleans | same prefix, question form | `IsValid`, `vHasRows`, `aCanEdit` |
|
|
27
|
+
| Test methods | short PascalCase; scenario in the XML `<summary>` | `LoginRejectsBadPassword` |
|
|
28
|
+
| Environment variables | PascalCase, no separators; read through `IConfiguration` via a provider that maps them to `Section:Key` | `AppManagerBaseUrl` |
|
|
29
|
+
|
|
30
|
+
Rejected: `_field` prefixes, snake_case, Hungarian type prefixes (`strName`), `Method_State_Result` test names, `UPPER_SNAKE` or `Section__Key` environment variables.
|
|
31
|
+
|
|
32
|
+
Controller actions: the `a` prefix applies to `[FromRoute]`, `[FromQuery]` and `[FromBody]` parameters and flows into the OpenAPI schema. DTO **property** names stay PascalCase without prefix.
|
|
33
|
+
|
|
34
|
+
## 2. Database
|
|
35
|
+
|
|
36
|
+
- PascalCase, singular table names: `CustomerOrder`. PascalCase columns: `FirstName`.
|
|
37
|
+
- Primary key `<Table>Id`; foreign key `<ReferencedTable>Id`.
|
|
38
|
+
- Stored procedures and functions: verb prefix, PascalCase: `GetCustomerOrders`, `InsertOrder`.
|
|
39
|
+
- Index `IX<Table><Column>` · primary key `Pk<Table>` · foreign key `Fk<Table><Ref>` · unique `Uc<Table><Column>`.
|
|
40
|
+
- Data access is Dapper. Migrations live in a dedicated `<App>Db` project using DbUp, run at application startup or by the pipeline. Never a `database` folder of loose scripts at the root.
|
|
41
|
+
|
|
42
|
+
## 3. Projects and files
|
|
43
|
+
|
|
44
|
+
- `src/` and `tests/` at the root. The primary head is `src/<App>/<App>.csproj`; `<App>.App` is banned. Secondary heads take a descriptive suffix: `<App>.Api`, `<App>.Desktop`, `<App>.Cli`. Satellites: `<App>.Core`, `<App>UI` (Razor class library), `<App>.Tests`.
|
|
45
|
+
- One class per file; file-scoped namespaces; nullable reference types enabled.
|
|
46
|
+
- File order: usings, namespace, type; inside the type: fields, constructor, properties, methods.
|
|
47
|
+
- Configuration: `appsettings.json` layered by `appsettings.{Environment}.json`; development secrets in `dotnet user-secrets`, with a `secrets.example.json` listing every key. No second mechanism.
|
|
48
|
+
|
|
49
|
+
## 4. Code
|
|
50
|
+
|
|
51
|
+
- Methods under about 20 lines; single responsibility; at most three levels of nesting; early returns.
|
|
52
|
+
- `async`/`await` for all I/O; `ConfigureAwait(false)` in libraries; no `async void` outside event handlers.
|
|
53
|
+
- LINQ method syntax for simple queries; avoid multiple enumeration.
|
|
54
|
+
- `StringBuilder` in loops; dispose `IDisposable`; cache expensive work.
|
|
55
|
+
- XML documentation on every public member: `<summary>`, `<param>`, `<returns>`, `<exception>`; `<remarks>` where the flow is not obvious.
|
|
56
|
+
|
|
57
|
+
## 5. Tests
|
|
58
|
+
|
|
59
|
+
- xUnit. A test project from day one.
|
|
60
|
+
- Short PascalCase names, scenario in `<summary>`; arrange, act, assert; one assertion per test where practical.
|
|
61
|
+
|
|
62
|
+
## 6. Logging
|
|
63
|
+
|
|
64
|
+
- Serilog with a rolling file sink in every executable head (web, API, MAUI, desktop, console, background service), wired before anything else can fail: `Log.Logger = new LoggerConfiguration().MinimumLevel.Information().WriteTo.Console().WriteTo.File("<build output>/logs/<app>-.log", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 14).CreateLogger();` then `builder.Services.AddSerilog()` or `builder.Host.UseSerilog()`; MAUI: `builder.Logging.AddSerilog()` in `MauiProgram`, path under `FileSystem.AppDataDirectory`.
|
|
65
|
+
- `Log.Fatal` around startup, handlers for `AppDomain.CurrentDomain.UnhandledException` and `TaskScheduler.UnobservedTaskException`, `Log.CloseAndFlush()` on exit.
|
|
66
|
+
- Class libraries reference only `Microsoft.Extensions.Logging.Abstractions` and log through `ILogger<T>` with structured templates.
|
|
67
|
+
- Brownfield: an existing structured file-logging stack is compliant; new heads still use Serilog.
|
|
68
|
+
|
|
69
|
+
## 7. Testability
|
|
70
|
+
|
|
71
|
+
- Blazor: a stable `data-testid` (or element id) on every control the verifier must reach.
|
|
72
|
+
- MAUI: a stable, unique `AutomationId` on every interactive or data-bound control, named by intent (`LoginSubmitButton`, `ClientsGrid`), set on the element whose data the gate asserts.
|
|
73
|
+
|
|
74
|
+
## 8. Security
|
|
75
|
+
|
|
76
|
+
- No credentials in code. Parameterised queries. Validate inputs. Log security events.
|
|
77
|
+
|
|
78
|
+
## 9. Enforcement
|
|
79
|
+
|
|
80
|
+
`.editorconfig` at the repository root (created at day-1) enforces: file-scoped namespaces (warning), `Async` suffix (warning), `var` for locals (warning), nullable enabled, no `_` prefix on private fields (custom naming rule, warning). `StyleCop.Analyzers` is optional and off by default.
|
|
81
|
+
|
|
82
|
+
The verifier's standards check runs:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# underscore-prefixed fields
|
|
86
|
+
grep -rE "private(\s+readonly)?\s+\w+\s+_[a-z]" src/ 2>/dev/null
|
|
87
|
+
# underscores in test method names
|
|
88
|
+
grep -rE "public\s+(async\s+)?Task\s+\w+_\w+\s*\(" tests/ 2>/dev/null
|
|
89
|
+
# fields missing the obj prefix (obj-style projects only)
|
|
90
|
+
grep -rPE "private(\s+readonly)?\s+\w+\s+(?!obj)[A-Z]\w+\s*[;=]" src/ 2>/dev/null | grep -v "static\|const"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Severity: error for file-scoped namespace and underscore field prefix; warning for nullable and the `Async` suffix; the rest informational.
|