hstack 0.7.1 → 0.17.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/CHANGELOG.md +308 -0
- package/README.md +90 -154
- package/VERSION +1 -1
- package/dist/commands/doctor.js +69 -9
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +7 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.js +17 -4
- package/dist/commands/update.js.map +1 -1
- package/dist/lib/descriptions.js +160 -0
- package/dist/lib/descriptions.js.map +1 -0
- package/dist/lib/diff.js +1 -1
- package/dist/lib/git.js +16 -0
- package/dist/lib/git.js.map +1 -1
- package/dist/lib/wire.js +274 -142
- package/dist/lib/wire.js.map +1 -1
- package/dist/manifest.js +49 -22
- package/dist/manifest.js.map +1 -1
- package/package.json +4 -3
- package/template/.claude/agents/adversarial-reviewer.md +42 -98
- package/template/.claude/agents/app-architect.md +44 -133
- package/template/.claude/agents/data-architect.md +46 -127
- package/template/.claude/agents/test-strategist.md +39 -109
- package/template/.claude/skills/hstack-adr-new/SKILL.md +23 -100
- package/template/.claude/skills/hstack-adversarial-review/SKILL.md +47 -174
- package/template/.claude/skills/hstack-adversarial-review/references/finding-categories.md +134 -0
- package/template/.claude/skills/hstack-app-architecture/SKILL.md +43 -95
- package/template/.claude/skills/hstack-commit/SKILL.md +28 -97
- package/template/.claude/skills/hstack-data-architecture/SKILL.md +34 -82
- package/template/.claude/skills/hstack-promote/SKILL.md +55 -0
- package/template/.claude/skills/hstack-story/SKILL.md +58 -0
- package/template/.claude/skills/hstack-test-audit/SKILL.md +64 -0
- package/template/.claude/skills/hstack-wrap/SKILL.md +48 -0
- package/template/.claude/skills/hstack-wrap/references/pr-description.md +45 -0
- package/template/KERNEL.md +167 -0
- package/template/templates/adr.md +9 -18
- package/template/templates/app-architecture.md +38 -50
- package/template/templates/data-architecture.md +39 -93
- package/template/templates/infrastructure.md +54 -148
- package/template/templates/roadmap.md +35 -0
- package/template/templates/story.md +7 -13
- package/template/templates/tech-debt.md +2 -37
- package/template/templates/tech-stack.md +2 -12
- package/template/.claude/agents/data-specialist.md +0 -126
- package/template/.claude/agents/implementer.md +0 -154
- package/template/.claude/agents/kernel-fit-analyst.md +0 -190
- package/template/.claude/agents/planner.md +0 -110
- package/template/.claude/agents/product-discovery.md +0 -165
- package/template/.claude/agents/product-manager.md +0 -111
- package/template/.claude/agents/researcher.md +0 -123
- package/template/.claude/agents/security-reviewer.md +0 -123
- package/template/.claude/agents/spec-author.md +0 -123
- package/template/.claude/agents/stack-architect.md +0 -137
- package/template/.claude/agents/ui-ux-briefer.md +0 -105
- package/template/.claude/agents/verifier.md +0 -113
- package/template/.claude/skills/hstack-branch/SKILL.md +0 -103
- package/template/.claude/skills/hstack-brownfield-init/SKILL.md +0 -158
- package/template/.claude/skills/hstack-change-new/SKILL.md +0 -111
- package/template/.claude/skills/hstack-change-plan/SKILL.md +0 -119
- package/template/.claude/skills/hstack-configure/SKILL.md +0 -126
- package/template/.claude/skills/hstack-coord/SKILL.md +0 -131
- package/template/.claude/skills/hstack-data-review/SKILL.md +0 -132
- package/template/.claude/skills/hstack-finalize/SKILL.md +0 -159
- package/template/.claude/skills/hstack-flag/SKILL.md +0 -138
- package/template/.claude/skills/hstack-greenfield-init/SKILL.md +0 -175
- package/template/.claude/skills/hstack-help/SKILL.md +0 -179
- package/template/.claude/skills/hstack-implement/SKILL.md +0 -185
- package/template/.claude/skills/hstack-kernel-fit-promote/SKILL.md +0 -164
- package/template/.claude/skills/hstack-kernel-fit-scan/SKILL.md +0 -197
- package/template/.claude/skills/hstack-kernel-fit-triage/SKILL.md +0 -159
- package/template/.claude/skills/hstack-module-spec/SKILL.md +0 -105
- package/template/.claude/skills/hstack-product-discovery/SKILL.md +0 -101
- package/template/.claude/skills/hstack-research/SKILL.md +0 -145
- package/template/.claude/skills/hstack-scaffold/SKILL.md +0 -140
- package/template/.claude/skills/hstack-security-review/SKILL.md +0 -133
- package/template/.claude/skills/hstack-ship/SKILL.md +0 -129
- package/template/.claude/skills/hstack-stack-decide/SKILL.md +0 -108
- package/template/.claude/skills/hstack-story-draft/SKILL.md +0 -119
- package/template/.claude/skills/hstack-tech-debt-new/SKILL.md +0 -122
- package/template/.claude/skills/hstack-tech-debt-resolve/SKILL.md +0 -158
- package/template/.claude/skills/hstack-tech-debt-stale/SKILL.md +0 -113
- package/template/.claude/skills/hstack-tech-debt-wontfix/SKILL.md +0 -104
- package/template/.claude/skills/hstack-telemetry/SKILL.md +0 -98
- package/template/.claude/skills/hstack-test-plan/SKILL.md +0 -182
- package/template/.claude/skills/hstack-ui-brief/SKILL.md +0 -108
- package/template/.claude/skills/hstack-verify/SKILL.md +0 -150
- package/template/CLAUDE.md +0 -443
- package/template/scripts/coord/coord_scan.py +0 -681
- package/template/scripts/telemetry/__init__.py +0 -6
- package/template/scripts/telemetry/insights/__init__.py +0 -0
- package/template/scripts/telemetry/insights/contract_drift.py +0 -137
- package/template/scripts/telemetry/insights/kernel_fit.py +0 -438
- package/template/scripts/telemetry/insights/overengineering.py +0 -115
- package/template/scripts/telemetry/insights/quality_outcomes.py +0 -131
- package/template/scripts/telemetry/insights/token_economics.py +0 -129
- package/template/scripts/telemetry/insights/workflow_shape.py +0 -198
- package/template/scripts/telemetry/parsers/__init__.py +0 -0
- package/template/scripts/telemetry/parsers/bodies.py +0 -87
- package/template/scripts/telemetry/parsers/commits.py +0 -219
- package/template/scripts/telemetry/parsers/frontmatter.py +0 -322
- package/template/scripts/telemetry/parsers/transcripts.py +0 -181
- package/template/scripts/telemetry/render.py +0 -395
- package/template/scripts/telemetry/report.py +0 -138
- package/template/scripts/telemetry/run_kernel_fit.py +0 -91
- package/template/templates/adversarial-review.md +0 -54
- package/template/templates/bootstrap.md +0 -105
- package/template/templates/change-spec.md +0 -82
- package/template/templates/ci-cd.md +0 -27
- package/template/templates/coord-message.md +0 -55
- package/template/templates/data-review.md +0 -54
- package/template/templates/discovery/brainstorm.md +0 -69
- package/template/templates/discovery/forcing-questions.md +0 -76
- package/template/templates/discovery/project-brief.md +0 -53
- package/template/templates/figma-handoff.md +0 -38
- package/template/templates/glossary.md +0 -20
- package/template/templates/hardening-checklist.md +0 -73
- package/template/templates/incident-runbook.md +0 -57
- package/template/templates/kernel-fit-finding.md +0 -63
- package/template/templates/kernel-fit-flag.md +0 -52
- package/template/templates/module-spec.md +0 -49
- package/template/templates/mvp-scope.md +0 -34
- package/template/templates/persona.md +0 -38
- package/template/templates/plan.md +0 -49
- package/template/templates/product-brief.md +0 -56
- package/template/templates/security-review.md +0 -63
- package/template/templates/telemetry-sidecar.md +0 -184
- package/template/templates/test-plan.md +0 -119
- package/template/templates/threat-model.md +0 -54
- package/template/templates/ui-brief.md +0 -49
- package/template/templates/verification.md +0 -63
- package/template/templates/vision.md +0 -34
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: <parent-change-id>-plan
|
|
3
|
-
type: plan
|
|
4
|
-
status: draft # draft | ready | in-progress | completed | archived
|
|
5
|
-
owner: <git-handle>
|
|
6
|
-
parent-change: <change-spec-id>
|
|
7
|
-
steps-completed: [] # populated by `implementer` as phases finish
|
|
8
|
-
blocked-on: null # phase id when an interactive blocker stops progress
|
|
9
|
-
oversized-plan-justification: null # required when phase count > 12
|
|
10
|
-
created: <YYYY-MM-DD>
|
|
11
|
-
updated: <YYYY-MM-DD>
|
|
12
|
-
schema-version: 1
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Phase Overview
|
|
16
|
-
|
|
17
|
-
_Table of phases. Three columns max._
|
|
18
|
-
|
|
19
|
-
| step-id | summary | depends-on |
|
|
20
|
-
| --- | --- | --- |
|
|
21
|
-
| phase-1- | | none |
|
|
22
|
-
|
|
23
|
-
## Per-Phase Detail
|
|
24
|
-
|
|
25
|
-
_One subsection per phase. 4–8 phases typical. >12 requires `oversized-plan-justification` in frontmatter._
|
|
26
|
-
|
|
27
|
-
### phase-1-
|
|
28
|
-
|
|
29
|
-
**Purpose.** _One sentence._
|
|
30
|
-
|
|
31
|
-
**Files Touched.** _Subset of `change-spec.in-scope`. Bullets._
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
**Test Strategy.** _Pointer to the test-plan section(s) this phase satisfies. Format: `test-plan §<section> — <one-line summary>`. The phase lands the tests named in the referenced section; do not restate or invent tests here. If this phase's work is exclusively non-test (e.g., a migration whose tests live in a later phase), state that explicitly and name the downstream phase that closes the loop._
|
|
36
|
-
|
|
37
|
-
**Risk.** _One sentence on what could go wrong locally._
|
|
38
|
-
|
|
39
|
-
**Verifier Expectations.** _What `verifier` must observe to mark this phase passed. References both this plan's Test Strategy and the test-plan sections the phase satisfies._
|
|
40
|
-
|
|
41
|
-
## Cross-Phase Risks
|
|
42
|
-
|
|
43
|
-
_Challenge prompt: what could go wrong across phase boundaries that no single phase catches? 1–3 bullets._
|
|
44
|
-
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
## Rollback
|
|
48
|
-
|
|
49
|
-
_What to do if a partial rollout in production breaks something. 2–4 sentences._
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: product-brief
|
|
3
|
-
type: product-brief
|
|
4
|
-
status: draft # draft | current | needs-refresh | archived
|
|
5
|
-
owner: <git-handle>
|
|
6
|
-
technique-used: <brainstorm | forcing-questions | project-brief>
|
|
7
|
-
derived-from: [] # always empty — product-brief is Phase 1, no upstream
|
|
8
|
-
downstream: [vision, mvp-scope, personas, glossary]
|
|
9
|
-
created: <YYYY-MM-DD>
|
|
10
|
-
updated: <YYYY-MM-DD>
|
|
11
|
-
schema-version: 1
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Underlying Pain
|
|
15
|
-
|
|
16
|
-
_What the user actually struggles with on a Tuesday morning, in concrete terms. Not "users want X" — "this specific person spends 20 minutes doing Y and misses Z." One paragraph, 4–8 sentences. The forcing-prompt reframes should have moved this away from the founder's first articulation; the result lands here._
|
|
17
|
-
|
|
18
|
-
## Target User
|
|
19
|
-
|
|
20
|
-
_A named, specific user (not "users", not "customers") with a workday vignette. Includes role, company-size band, tools they use today, the workflow this product enters. If multiple personas matter for v1, name them all — but each must pass the concreteness floor._
|
|
21
|
-
|
|
22
|
-
## Value Proposition
|
|
23
|
-
|
|
24
|
-
_What this product delivers to the named user, in their language. One paragraph. Distinct from features — this is the outcome they buy._
|
|
25
|
-
|
|
26
|
-
## Smallest Useful Wedge
|
|
27
|
-
|
|
28
|
-
_The minimum shippable surface that delivers real value to the named user. Forcing-prompt answer: "Would the named user still pay for this if you shipped only the wedge and nothing else?" Yes required; if no, the wedge is too large or the user is wrong._
|
|
29
|
-
|
|
30
|
-
## Success Criteria
|
|
31
|
-
|
|
32
|
-
_Concrete, measurable, time-bound. "Maya saves 10 minutes per QBR prep within 4 weeks of activation" not "users love it." At least one criterion; more is better._
|
|
33
|
-
|
|
34
|
-
## Explicitly NOT
|
|
35
|
-
|
|
36
|
-
_Two-bullet minimum. The boundaries of the product. What this is NOT, what it does NOT do, what populations it does NOT serve. Required, never optional — over-broad scoping is the #1 product failure mode._
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
## Open Risks
|
|
42
|
-
|
|
43
|
-
_The things that could make this product fail. The forcing-prompt "What would you have to believe to be wrong about this?" answer lands here. At least one risk; more is better._
|
|
44
|
-
|
|
45
|
-
## Forcing-Prompt Answers
|
|
46
|
-
|
|
47
|
-
_Evidence that the three required reframes ran. Logged inline as confirmation the probes were not skipped._
|
|
48
|
-
|
|
49
|
-
**Who specifically pays for this?**
|
|
50
|
-
_The named user / buyer plus the rationale ("Director of CS, because retention is their KPI")._
|
|
51
|
-
|
|
52
|
-
**What's the smallest useful wedge?**
|
|
53
|
-
_The wedge plus the rationale ("Change-awareness alone, because the rest of the workflow is downstream of it")._
|
|
54
|
-
|
|
55
|
-
**What would you have to believe to be wrong about this?**
|
|
56
|
-
_The belief plus the falsifiability angle ("That CS reps will trust LLM-generated summaries — wrong if they require human-curated context")._
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: <parent-change-id>-security-review
|
|
3
|
-
type: security-review
|
|
4
|
-
status: draft # draft | in-progress | passed | concerns-acknowledged | failed | superseded
|
|
5
|
-
owner: <git-handle>
|
|
6
|
-
parent-change: <change-spec-id>
|
|
7
|
-
scoring-mode: llm-scored # v1; v2 introduces 'executed'
|
|
8
|
-
scores:
|
|
9
|
-
data-at-rest: not-applicable # pass | concerns | fail | not-applicable
|
|
10
|
-
data-in-transit: not-applicable
|
|
11
|
-
authn: not-applicable
|
|
12
|
-
authz-rls: not-applicable
|
|
13
|
-
tenant-isolation: not-applicable
|
|
14
|
-
input-validation: not-applicable
|
|
15
|
-
output-encoding: not-applicable
|
|
16
|
-
secrets-handling: not-applicable
|
|
17
|
-
agent-prompt-injection: not-applicable
|
|
18
|
-
audit-logging: not-applicable
|
|
19
|
-
concerns-acknowledged-by: null # handle required when any score is `concerns`
|
|
20
|
-
threat-model-delta-required: false # true when surfaces touches agent | auth | api | db
|
|
21
|
-
challenge-prompts-answered: 0 # must equal 3 to pass
|
|
22
|
-
created: <YYYY-MM-DD>
|
|
23
|
-
updated: <YYYY-MM-DD>
|
|
24
|
-
schema-version: 1
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## Surfaces Touched
|
|
28
|
-
|
|
29
|
-
_Pointer to change-spec `surfaces`. One sentence per surface._
|
|
30
|
-
|
|
31
|
-
## Hardening Items Scored
|
|
32
|
-
|
|
33
|
-
_For every applicable checklist item, a one-paragraph rationale for the score. Bias toward CONCERNS rather than PASS when evidence is thin._
|
|
34
|
-
|
|
35
|
-
### data-at-rest
|
|
36
|
-
|
|
37
|
-
### data-in-transit
|
|
38
|
-
|
|
39
|
-
### authz-rls
|
|
40
|
-
|
|
41
|
-
### tenant-isolation
|
|
42
|
-
|
|
43
|
-
### input-validation
|
|
44
|
-
|
|
45
|
-
### audit-logging
|
|
46
|
-
|
|
47
|
-
## Threat-Model Delta
|
|
48
|
-
|
|
49
|
-
_Required when `threat-model-delta-required: true`. One paragraph delta against the current threat-model.md. Refuse to score until this is non-empty when surfaces require it._
|
|
50
|
-
|
|
51
|
-
## Challenge Prompts
|
|
52
|
-
|
|
53
|
-
_All three required. Each answer must be at least one paragraph._
|
|
54
|
-
|
|
55
|
-
### (a) What attack vector did the In-Scope diff create that is NOT covered by the hardening checklist? If none, justify.
|
|
56
|
-
|
|
57
|
-
### (b) Which tenant_isolation guarantee does this change depend on? Cite the line of code that enforces it.
|
|
58
|
-
|
|
59
|
-
### (c) What part of this change would behave incorrectly under a malicious payload that the test suite does not cover?
|
|
60
|
-
|
|
61
|
-
## Open Concerns
|
|
62
|
-
|
|
63
|
-
_When any score is `concerns`: what acknowledgement is required and by whom. Ack must be human-confirmed by `owner` before status: concerns-acknowledged._
|
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
# Telemetry sidecar — schema and discipline
|
|
2
|
-
|
|
3
|
-
This document describes the JSON sidecar files three hstack Skills emit alongside their canonical artifact writes, to make per-change telemetry attribution cheap. Sidecars are **derivative** of git + frontmatter — re-runnable from source, never authoritative. The kernel's "no parallel tracker" rule is preserved by this derivative property.
|
|
4
|
-
|
|
5
|
-
## Where sidecars live
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
hstack/specs/changes/<change-id>/.telemetry/
|
|
9
|
-
test-plan.json # one per test-plan terminal status
|
|
10
|
-
implement-<phase-id>.json # one per implement phase
|
|
11
|
-
verify.json # one per verify pass
|
|
12
|
-
adversarial-review.json # one per adversarial-review terminal status
|
|
13
|
-
finalize.json # one per ship
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
The `.telemetry/` directory is **git-ignored** at the consuming-repo level. Sidecars are transient; the canonical truth lives in the artifact frontmatter and git history.
|
|
17
|
-
|
|
18
|
-
## When sidecars are written
|
|
19
|
-
|
|
20
|
-
| Skill | Trigger | File |
|
|
21
|
-
| --- | --- | --- |
|
|
22
|
-
| `hstack-test-plan` | At the test-plan terminal-status commit (`passed` or `concerns-acknowledged`) | `test-plan.json` |
|
|
23
|
-
| `hstack-implement` | At each phase-completion auto-commit (the same `git add && git commit` that lands `plan.steps-completed`) | `implement-<phase-id>.json` |
|
|
24
|
-
| `hstack-verify` | At the change-spec advance commit when `verification.md` lands at `status: passed` (per ADR-0002); on `ran`/`failed`, piggybacks on the verification status commit | `verify.json` |
|
|
25
|
-
| `hstack-adversarial-review` | At the change-spec advance commit when `adversarial-review.md` lands at `findings-resolved` (per ADR-0002 follow-up); on `findings-open`/`in-progress`, piggybacks on the transition commit | `adversarial-review.json` |
|
|
26
|
-
| `hstack-finalize` | At the change-spec advance commit when status moves `ready-to-ship → shipped` | `finalize.json` |
|
|
27
|
-
|
|
28
|
-
The other 22 Skills do **not** emit sidecars in v1. Their data is reconstructible from git + frontmatter + transcripts; the five emissions above target the highest-signal events across the change lifecycle: test discipline up front (`test-plan`), per-phase scope-locked execution (`implement`), promised-vs-observed (`verify`), gate-firing critique (`adversarial-review`), lifecycle close (`finalize`).
|
|
29
|
-
|
|
30
|
-
## Schema — `test-plan.json`
|
|
31
|
-
|
|
32
|
-
```json
|
|
33
|
-
{
|
|
34
|
-
"schema_version": 1,
|
|
35
|
-
"skill": "hstack-test-plan",
|
|
36
|
-
"change_id": "2026-05-billing-overage-warning",
|
|
37
|
-
"completed_at": "2026-05-22T11:14:00Z",
|
|
38
|
-
"status": "passed",
|
|
39
|
-
"coverage_layers": {"unit": "addressed", "integration": "addressed", "e2e": "not-applicable"},
|
|
40
|
-
"tenant_isolation_tests_count": 0,
|
|
41
|
-
"tenant_isolation_required": false,
|
|
42
|
-
"performance_budgets_required": false,
|
|
43
|
-
"performance_budgets_count": 0,
|
|
44
|
-
"challenge_prompts_answered": 3,
|
|
45
|
-
"invariants_mapped_count": 4,
|
|
46
|
-
"invariants_declared_count": 4,
|
|
47
|
-
"edge_cases_count": 5,
|
|
48
|
-
"test_files_named_count": 7,
|
|
49
|
-
"fixture_strategy_declared": true,
|
|
50
|
-
"halt_reasons": []
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Field rules:
|
|
55
|
-
|
|
56
|
-
- `tenant_isolation_tests_count` paired with `tenant_isolation_required` is the rubber-stamp tell. `required: true` with `count: 0` at terminal status is a TS-03 contract violation that should have halted the Skill — its presence in a `passed` sidecar is a high-severity signal.
|
|
57
|
-
- `challenge_prompts_answered` must be exactly `3` for `passed`. Lower values at `passed` indicate either a validator gap or a Skill bypass.
|
|
58
|
-
- `invariants_mapped_count` lower than `invariants_declared_count` at `passed` is a TS-06 violation. Same signal-handling as above.
|
|
59
|
-
|
|
60
|
-
## Schema — `implement-<phase-id>.json`
|
|
61
|
-
|
|
62
|
-
```json
|
|
63
|
-
{
|
|
64
|
-
"schema_version": 1,
|
|
65
|
-
"skill": "hstack-implement",
|
|
66
|
-
"change_id": "2026-05-billing-overage-warning",
|
|
67
|
-
"phase_id": "phase-3-component",
|
|
68
|
-
"started_at": "2026-05-22T14:00:00Z",
|
|
69
|
-
"completed_at": "2026-05-22T14:18:42Z",
|
|
70
|
-
"files_touched_count": 4,
|
|
71
|
-
"tests_written_count": 2,
|
|
72
|
-
"scope_amendment_emitted": false,
|
|
73
|
-
"halt_reasons": [],
|
|
74
|
-
"test_immutability_authorizations": []
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Field rules:
|
|
79
|
-
|
|
80
|
-
- `started_at`, `completed_at` — ISO-8601. The implementer records them from session timestamps.
|
|
81
|
-
- `files_touched_count` — count of distinct files modified by the phase's commit. Computed mechanically; not a judgment.
|
|
82
|
-
- `tests_written_count` — count of test files newly created in the phase (kernel test-immutability rule allows new tests without authorization).
|
|
83
|
-
- `scope_amendment_emitted` — `true` only when the implementer halted and surfaced a scope-amendment request during this phase.
|
|
84
|
-
- `halt_reasons` — array of enum values from the kernel halt sentinel (see CLAUDE.md § Halt sentinel).
|
|
85
|
-
- `test_immutability_authorizations` — array of canonical authorization phrases echoed during this phase (e.g., `"Ok to change test foo"`).
|
|
86
|
-
|
|
87
|
-
## Schema — `verify.json`
|
|
88
|
-
|
|
89
|
-
```json
|
|
90
|
-
{
|
|
91
|
-
"schema_version": 1,
|
|
92
|
-
"skill": "hstack-verify",
|
|
93
|
-
"change_id": "2026-05-billing-overage-warning",
|
|
94
|
-
"ran_at": "2026-05-22T15:32:00Z",
|
|
95
|
-
"test_suite_runtime_s": 187.4,
|
|
96
|
-
"phase_coverage": {"phase-1-types": "pass", "phase-2-component": "pass"},
|
|
97
|
-
"test_plan_coverage": {
|
|
98
|
-
"edge-cases": "all-observed",
|
|
99
|
-
"tenant-isolation": "not-applicable",
|
|
100
|
-
"performance-budgets": "not-applicable"
|
|
101
|
-
},
|
|
102
|
-
"discrepancies_count": 0,
|
|
103
|
-
"status": "passed"
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
Field rules:
|
|
108
|
-
|
|
109
|
-
- `test_suite_runtime_s` — float seconds. Wall-clock elapsed across all canonical commands.
|
|
110
|
-
- `phase_coverage`, `test_plan_coverage` — mirror `verification.md` frontmatter for cheap downstream parsing. When verification fails, the sidecar still lands at the corresponding `ran` or `failed` status; the canonical artifact is the source of truth for any discrepancy.
|
|
111
|
-
- `discrepancies_count` — count of bullet points under `verification.md § Discrepancies`. A non-zero value should always pair with a non-empty Discrepancies section in the canonical artifact.
|
|
112
|
-
|
|
113
|
-
## Schema — `adversarial-review.json`
|
|
114
|
-
|
|
115
|
-
```json
|
|
116
|
-
{
|
|
117
|
-
"schema_version": 1,
|
|
118
|
-
"skill": "hstack-adversarial-review",
|
|
119
|
-
"change_id": "2026-05-billing-overage-warning",
|
|
120
|
-
"reviewed_at": "2026-05-22T16:42:00Z",
|
|
121
|
-
"findings_floor": 5,
|
|
122
|
-
"findings_count": 6,
|
|
123
|
-
"findings_fewer_than_floor": false,
|
|
124
|
-
"category_counts": {
|
|
125
|
-
"security": 1,
|
|
126
|
-
"scope-drift": 0,
|
|
127
|
-
"invariant-breach": 1,
|
|
128
|
-
"spec-compliance": 2,
|
|
129
|
-
"data-integrity": 1,
|
|
130
|
-
"code-quality": 1
|
|
131
|
-
},
|
|
132
|
-
"severity_counts": {"critical": 0, "high": 1, "medium": 3, "low": 2},
|
|
133
|
-
"resolution_mix": {"commit": 4, "tech-debt": 1, "justified-in-prose": 1},
|
|
134
|
-
"fresh_session_attestation": "session abc-123; opened 2026-05-22T16:40Z; no implementer transcripts loaded",
|
|
135
|
-
"halt_reasons": []
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
Field rules:
|
|
140
|
-
|
|
141
|
-
- `findings_floor` is `3` by default, `5` when `change-spec.area` is in `{agent, auth, billing}` per AR-06.
|
|
142
|
-
- `findings_count` < `findings_floor` is permitted only when `findings_fewer_than_floor: true` (with a defended justification in the canonical artifact's Findings Floor Justification section). Aggregating across changes: a rising `findings_fewer_than_floor: true` rate means either the floors are wrong or the reviewer is gaming the escape hatch.
|
|
143
|
-
- `category_counts` clustering — e.g., 5 of 5 findings in `code-quality` — is the quota-gaming smell the kernel's "spread findings across categories" guidance is designed to detect. The telemetry layer surfaces it via OE-7.
|
|
144
|
-
- `severity_counts.high + critical` paired with `resolution_mix.justified-in-prose > 0` is a high-severity-in-prose smell flagged by QO-2. The Skill's stop condition should have caught it before terminal status; sidecar presence indicates a bypass.
|
|
145
|
-
|
|
146
|
-
## Schema — `finalize.json`
|
|
147
|
-
|
|
148
|
-
```json
|
|
149
|
-
{
|
|
150
|
-
"schema_version": 1,
|
|
151
|
-
"skill": "hstack-finalize",
|
|
152
|
-
"change_id": "2026-05-billing-overage-warning",
|
|
153
|
-
"shipped_at": "2026-05-23T10:14:00Z",
|
|
154
|
-
"merge_commit_sha": "abc1234567890",
|
|
155
|
-
"change_duration_days": 4,
|
|
156
|
-
"tds_resolved": ["TD-0042-overage-banner-tailwind-class"]
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
Field rules:
|
|
161
|
-
|
|
162
|
-
- `merge_commit_sha` — full SHA of the merge commit on the default branch.
|
|
163
|
-
- `change_duration_days` — integer days from `change-spec.created` to the merge commit's author date.
|
|
164
|
-
- `tds_resolved` — list of TD ids; mirrors `change-spec.resolves-tech-debt`. Empty array on changes that resolve no debt.
|
|
165
|
-
|
|
166
|
-
## Discipline preserved
|
|
167
|
-
|
|
168
|
-
Per the kernel § Mechanical operations § Discipline preserved:
|
|
169
|
-
|
|
170
|
-
- **Atomic with the canonical commit.** Each sidecar is written and `git add`-ed in the same commit as the canonical artifact write. No separate commit. The sidecar piggybacks on a commit that was happening anyway — zero new LLM turns, zero new confirmation gates.
|
|
171
|
-
- **Idempotency.** Re-running a Skill on a phase that already landed produces a no-op on the sidecar (file already present, content unchanged aside from `schema_version` bumps if any).
|
|
172
|
-
- **Derivative property.** Every value in every sidecar is reconstructible from git + frontmatter + transcripts. The sidecar is a cache, not a source. Deleting a sidecar is harmless — the next `/hstack:telemetry` run will compute the same metrics from the slower path.
|
|
173
|
-
- **Schema versioning.** `schema_version: 1` in v1. Bumping to `2` requires either a backward-compatible additive change (new optional field) or a migration in `scripts/telemetry/parsers/`.
|
|
174
|
-
|
|
175
|
-
## What sidecars are NOT
|
|
176
|
-
|
|
177
|
-
- Not authoritative. The artifact frontmatter and git history are. If a sidecar disagrees with the artifact, the artifact wins.
|
|
178
|
-
- Not an audit trail. The kernel reserves "agent-ledger" naming for the v2 substrate when it ships with cryptographic guarantees.
|
|
179
|
-
- Not blocking. A sidecar write failure is logged but does not block the canonical commit.
|
|
180
|
-
- Not a parallel tracker. The kernel forbids parallel trackers; sidecars survive that rule only because they are derivative.
|
|
181
|
-
|
|
182
|
-
## Adding sidecar emission to a new Skill
|
|
183
|
-
|
|
184
|
-
The v1 emission list is fixed at five Skills (`test-plan`, `implement`, `verify`, `adversarial-review`, `finalize`). Adding a sixth is a follow-up change-spec, not a unilateral Skill edit. The cost-benefit threshold: a Skill is sidecar-eligible when its terminal event is per-change (not per-session), the data the sidecar would carry is non-trivial to reconstruct from git alone, and the Skill already auto-commits at the terminal event (no new commit needed). The "tier 2" candidates already evaluated and held back are `hstack-security-review` and `hstack-data-review`; both pass the criteria but their data is already first-class in frontmatter, so the sidecar's only value is parse-cost reduction. Promote them when WS-2 body parsing becomes a felt bottleneck.
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: <parent-change-id>-test-plan
|
|
3
|
-
type: test-plan
|
|
4
|
-
status: draft # draft | in-progress | passed | concerns-acknowledged | failed | superseded
|
|
5
|
-
owner: <git-handle>
|
|
6
|
-
parent-change: <change-spec-id>
|
|
7
|
-
scoring-mode: llm-strategized # v1; v2 introduces 'executed' once mutation/coverage tooling is wired
|
|
8
|
-
coverage-layers:
|
|
9
|
-
unit: not-applicable # addressed | partial | not-applicable
|
|
10
|
-
integration: not-applicable
|
|
11
|
-
e2e: not-applicable
|
|
12
|
-
tenant-isolation-tests: [] # required non-empty when surfaces includes db | api | agent
|
|
13
|
-
fixture-strategy-declared: false # must be true before status: passed
|
|
14
|
-
performance-budgets-required: false # true when change touches hot paths or high-traffic surfaces
|
|
15
|
-
challenge-prompts-answered: 0 # must equal 3
|
|
16
|
-
concerns-acknowledged-by: null # handle required when any coverage layer is `partial` and deferred
|
|
17
|
-
invariants-mapped: [] # change-spec invariant ids that have a mapped test in this plan
|
|
18
|
-
created: <YYYY-MM-DD>
|
|
19
|
-
updated: <YYYY-MM-DD>
|
|
20
|
-
schema-version: 1
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Surfaces and Risk Profile
|
|
24
|
-
|
|
25
|
-
_Pointer to change-spec `surfaces`. One sentence per surface naming the dominant test-risk layer it adds (e.g., "ui — interaction state regressions; db — RLS bypass risk on new table")._
|
|
26
|
-
|
|
27
|
-
## Test Pyramid
|
|
28
|
-
|
|
29
|
-
_Per-layer decisions: which behaviors land at which layer and why. Bias toward integration over end-to-end for behavior coverage; bias toward unit for pure functions and reducers. Name the test files that will exist; estimate count roughly. If a layer is `not-applicable`, justify in one sentence._
|
|
30
|
-
|
|
31
|
-
### unit
|
|
32
|
-
|
|
33
|
-
**Coverage status.** _addressed | partial | not-applicable._
|
|
34
|
-
|
|
35
|
-
**Files.** _Test files in scope (relative paths)._
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
|
|
39
|
-
**What's covered.** _Behaviors validated at this layer. 2–4 bullets._
|
|
40
|
-
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
**Rationale.** _Why this layer is the right home for these behaviors._
|
|
44
|
-
|
|
45
|
-
### integration
|
|
46
|
-
|
|
47
|
-
**Coverage status.**
|
|
48
|
-
|
|
49
|
-
**Files.**
|
|
50
|
-
|
|
51
|
-
-
|
|
52
|
-
|
|
53
|
-
**What's covered.**
|
|
54
|
-
|
|
55
|
-
-
|
|
56
|
-
|
|
57
|
-
**Rationale.**
|
|
58
|
-
|
|
59
|
-
### e2e
|
|
60
|
-
|
|
61
|
-
**Coverage status.**
|
|
62
|
-
|
|
63
|
-
**Files.**
|
|
64
|
-
|
|
65
|
-
-
|
|
66
|
-
|
|
67
|
-
**What's covered.**
|
|
68
|
-
|
|
69
|
-
-
|
|
70
|
-
|
|
71
|
-
**Rationale.**
|
|
72
|
-
|
|
73
|
-
## Edge Cases
|
|
74
|
-
|
|
75
|
-
_Enumerate the edge cases the change must handle, and name the test that catches each. Bias toward cases the change-spec's Target Behavior does not explicitly name — empty inputs, max-length inputs, concurrent writes, partial failure, retries, idempotency, time-zone boundaries, off-by-one on pagination, NULL vs empty-string, locale-sensitive formatting. Minimum three bullets unless the change is genuinely trivial. Format: `case → test file::test name`._
|
|
76
|
-
|
|
77
|
-
-
|
|
78
|
-
-
|
|
79
|
-
-
|
|
80
|
-
|
|
81
|
-
## Tenant Isolation Tests
|
|
82
|
-
|
|
83
|
-
_Required non-empty section when `surfaces` includes `db`, `api`, or `agent`. For every new RLS-protected table, new tenant-scoped RPC, new tool boundary, or new cross-tenant data path: name an explicit negative test that proves cross-tenant reads/writes are refused. The change-spec's `tenant_isolation` invariants must each map to at least one test here. Format: `surface → test file::test name → what it proves`._
|
|
84
|
-
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
## Test Data and Fixture Strategy
|
|
88
|
-
|
|
89
|
-
_Required section. How test data is seeded, what factories or fixtures are reused, how tests are isolated from each other, and how multi-tenant data is partitioned in test runs. Name the factory module or fixture file. State whether tests share a database between runs (transactional rollback per test, full reset per suite, in-memory mock) and why._
|
|
90
|
-
|
|
91
|
-
**Seed strategy.**
|
|
92
|
-
|
|
93
|
-
**Factory / fixture module.**
|
|
94
|
-
|
|
95
|
-
**Isolation between tests.**
|
|
96
|
-
|
|
97
|
-
**Multi-tenant partitioning.**
|
|
98
|
-
|
|
99
|
-
## Performance and Regression Budgets
|
|
100
|
-
|
|
101
|
-
_Required when `performance-budgets-required: true`. For each hot path the change touches, declare a numeric budget (p50/p95 latency, throughput, payload size, query count) and the test that asserts the budget. Budgets without an asserting test are not budgets; they are wishes._
|
|
102
|
-
|
|
103
|
-
| path | budget | asserting test |
|
|
104
|
-
| --- | --- | --- |
|
|
105
|
-
| | | |
|
|
106
|
-
|
|
107
|
-
## Challenge Prompts
|
|
108
|
-
|
|
109
|
-
_All three required. Each answer must be at least one paragraph. These exist because the v1 mitigation for "humans miss what's missing" is to force the strategist to name gaps the planner and the implementer will not._
|
|
110
|
-
|
|
111
|
-
### (a) What behavior in this change would silently pass the test suite but break in production? Name the test that would catch it, or declare that no such test is planned and justify.
|
|
112
|
-
|
|
113
|
-
### (b) Which invariant from the change-spec has no corresponding negative or regression test? If every invariant has a mapped test, cite the test for each invariant by id.
|
|
114
|
-
|
|
115
|
-
### (c) What concurrent, multi-tenant, or failure-mode scenario is not exercised by the planned tests? If none is plausibly relevant, justify why this change has no such scenario.
|
|
116
|
-
|
|
117
|
-
## Open Concerns
|
|
118
|
-
|
|
119
|
-
_When any coverage layer is `partial` and being deferred rather than addressed: enumerate what is uncovered, why it is acceptable to defer, who is acknowledging, and what tech-debt id captures the deferral. Ack must be human-confirmed by `owner` before status: concerns-acknowledged. Empty when every layer is `addressed` or `not-applicable`._
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: threat-model
|
|
3
|
-
type: threat-model
|
|
4
|
-
status: drafted # drafted | current | needs-refresh | archived
|
|
5
|
-
owner: <git-handle>
|
|
6
|
-
last-quarterly-review: <YYYY-MM-DD>
|
|
7
|
-
surfaces-covered: [ui, api, db, infra, agent]
|
|
8
|
-
created: <YYYY-MM-DD>
|
|
9
|
-
updated: <YYYY-MM-DD>
|
|
10
|
-
schema-version: 1
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
_One section per surface in `surfaces-covered` (validator rule TM-01). Each section enumerates concrete threats with: threat description, affected assets, mitigation, mitigation evidence (pointer to code, ADR, or hardening-checklist item). Length cap: 8 threats per surface._
|
|
14
|
-
|
|
15
|
-
## ui
|
|
16
|
-
|
|
17
|
-
### Threat: <name>
|
|
18
|
-
**Affected assets.**
|
|
19
|
-
**Mitigation.**
|
|
20
|
-
**Evidence.**
|
|
21
|
-
|
|
22
|
-
## api
|
|
23
|
-
|
|
24
|
-
### Threat: <name>
|
|
25
|
-
**Affected assets.**
|
|
26
|
-
**Mitigation.**
|
|
27
|
-
**Evidence.**
|
|
28
|
-
|
|
29
|
-
## db
|
|
30
|
-
|
|
31
|
-
### Threat: <name>
|
|
32
|
-
**Affected assets.**
|
|
33
|
-
**Mitigation.**
|
|
34
|
-
**Evidence.**
|
|
35
|
-
|
|
36
|
-
## infra
|
|
37
|
-
|
|
38
|
-
### Threat: <name>
|
|
39
|
-
**Affected assets.**
|
|
40
|
-
**Mitigation.**
|
|
41
|
-
**Evidence.**
|
|
42
|
-
|
|
43
|
-
## agent
|
|
44
|
-
|
|
45
|
-
### Threat: <name>
|
|
46
|
-
**Affected assets.**
|
|
47
|
-
**Mitigation.**
|
|
48
|
-
**Evidence.**
|
|
49
|
-
|
|
50
|
-
## Unknowns
|
|
51
|
-
|
|
52
|
-
_Challenge prompt: what threat to our multi-tenant boundary do you not yet have a mitigation for? This section must be present even when empty, to make the absence explicit (validator rule TM-02)._
|
|
53
|
-
|
|
54
|
-
-
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: <parent-change-id>-ui-brief
|
|
3
|
-
type: ui-brief
|
|
4
|
-
status: draft # draft | drafted | superseded
|
|
5
|
-
owner: <git-handle>
|
|
6
|
-
parent-change: <change-spec-id>
|
|
7
|
-
reused-components: [] # design-system component ids
|
|
8
|
-
new-components: [] # any non-empty entry requires a justification subsection
|
|
9
|
-
design-system-version: <version> # must match hstack/config.yaml
|
|
10
|
-
created: <YYYY-MM-DD>
|
|
11
|
-
updated: <YYYY-MM-DD>
|
|
12
|
-
schema-version: 1
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## Goal
|
|
16
|
-
|
|
17
|
-
_One paragraph. What the UI must achieve from the user's POV._
|
|
18
|
-
|
|
19
|
-
## Layouts and States
|
|
20
|
-
|
|
21
|
-
_For every visible state of every new or modified surface: layout, content, interaction. Paragraph or bullets per state._
|
|
22
|
-
|
|
23
|
-
## Reused Components
|
|
24
|
-
|
|
25
|
-
_Bullets pointing to existing components by design-system id._
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
## New Components
|
|
30
|
-
|
|
31
|
-
_For each: name, props, justification for not reusing. Challenge prompt: why is this new and not a reuse?_
|
|
32
|
-
|
|
33
|
-
### <ComponentName>
|
|
34
|
-
|
|
35
|
-
**Props.** `{ ... }`
|
|
36
|
-
|
|
37
|
-
**Justification.**
|
|
38
|
-
|
|
39
|
-
## Copy
|
|
40
|
-
|
|
41
|
-
_Exact strings the user sees. Reviewed by cofounder. Bullets._
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
|
|
45
|
-
## Accessibility Notes
|
|
46
|
-
|
|
47
|
-
_Anything that requires non-default handling (focus order, screen reader copy, contrast deviation). Bullets._
|
|
48
|
-
|
|
49
|
-
-
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: <parent-change-id>-verification
|
|
3
|
-
type: verification
|
|
4
|
-
status: draft # draft | ran | passed | failed | superseded
|
|
5
|
-
owner: <git-handle>
|
|
6
|
-
parent-change: <change-spec-id>
|
|
7
|
-
test-results:
|
|
8
|
-
unit: pending # pass | fail | pending | not-run
|
|
9
|
-
integration: pending
|
|
10
|
-
e2e: pending
|
|
11
|
-
lint: pending
|
|
12
|
-
typecheck: pending
|
|
13
|
-
phase-coverage: {} # mirror of plan.steps-completed; { <phase-id>: pass | fail }
|
|
14
|
-
test-plan-coverage: # observed-vs-promised against test-plan.md
|
|
15
|
-
edge-cases: pending # all-observed | partial | missing
|
|
16
|
-
tenant-isolation: pending # all-observed | partial | missing | not-applicable
|
|
17
|
-
performance-budgets: pending # all-within-budget | regressed | missing | not-applicable
|
|
18
|
-
artifacts:
|
|
19
|
-
test-output: <path>
|
|
20
|
-
created: <YYYY-MM-DD>
|
|
21
|
-
updated: <YYYY-MM-DD>
|
|
22
|
-
schema-version: 1
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## Summary
|
|
26
|
-
|
|
27
|
-
_Single-sentence verdict._
|
|
28
|
-
|
|
29
|
-
## Per-Phase Outcomes
|
|
30
|
-
|
|
31
|
-
_Table of phase id, verifier expectations met (yes/no), notes. Three columns max._
|
|
32
|
-
|
|
33
|
-
| phase-id | met | notes |
|
|
34
|
-
| --- | --- | --- |
|
|
35
|
-
| | | |
|
|
36
|
-
|
|
37
|
-
## Test-Plan Coverage
|
|
38
|
-
|
|
39
|
-
_Observed-vs-promised against `test-plan.md`. Three subsections; populate only those that apply to this change._
|
|
40
|
-
|
|
41
|
-
### Edge Cases
|
|
42
|
-
|
|
43
|
-
_Every bullet in the test-plan's Edge Cases section maps to an observed test. Absent or skipped tests are listed with a recommended action._
|
|
44
|
-
|
|
45
|
-
### Tenant Isolation
|
|
46
|
-
|
|
47
|
-
_Every entry in the test-plan's `tenant-isolation-tests` array maps to an observed negative test. Absences here are high-severity and escalate to adversarial-review (V-03)._
|
|
48
|
-
|
|
49
|
-
### Performance Budgets
|
|
50
|
-
|
|
51
|
-
_Every row in the test-plan's Budgets table maps to an observed assertion within budget. Regressions and absences block `status: passed` (V-04)._
|
|
52
|
-
|
|
53
|
-
| path | budget | observed | within budget |
|
|
54
|
-
| --- | --- | --- | --- |
|
|
55
|
-
| | | | |
|
|
56
|
-
|
|
57
|
-
## Test Suite Output
|
|
58
|
-
|
|
59
|
-
_Pointer to the captured stdout/stderr blob (`artifacts.test-output`)._
|
|
60
|
-
|
|
61
|
-
## Discrepancies
|
|
62
|
-
|
|
63
|
-
_Anything the verifier observed that the plan did not predict, with an action (file an issue, escalate to adversarial-review)._
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
id: vision
|
|
3
|
-
type: vision
|
|
4
|
-
status: drafted # drafted | current | needs-refresh | archived
|
|
5
|
-
owner: <git-handle>
|
|
6
|
-
reviewed-quarterly-on: <YYYY-MM-DD>
|
|
7
|
-
created: <YYYY-MM-DD>
|
|
8
|
-
updated: <YYYY-MM-DD>
|
|
9
|
-
schema-version: 1
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## What this product is
|
|
13
|
-
|
|
14
|
-
_Two or three sentences naming the product and category._
|
|
15
|
-
|
|
16
|
-
## What it does
|
|
17
|
-
|
|
18
|
-
_Top 3–5 user-visible capabilities. Bullets._
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
## What it explicitly is not
|
|
23
|
-
|
|
24
|
-
_Boundaries we are committing not to cross. Bullets._
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
|
|
28
|
-
## Who it is for
|
|
29
|
-
|
|
30
|
-
_Pointer to personas. Not a duplication of persona content._
|
|
31
|
-
|
|
32
|
-
## Why now
|
|
33
|
-
|
|
34
|
-
_The timing thesis. Two or three sentences._
|