Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/commands/pharn-dev-build.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ For each file the plan names in `## Files`:
- Determinism (P5): branches are membership tests; the terminal fallback is "ask", never a guess.

> Building a PHARN **markdown capability** (frontmatter contract, `evals/cases` + `evals/expected`,
> `seal:`) applies only when the increment adds one. pharn-cli is TypeScript — its "capabilities"
> `seal:`) applies only when the increment adds one. pharn is TypeScript — its "capabilities"
> are modules and its "evals" are vitest tests; the structural `validate.mjs` floor below stays
> vacuously-green until a markdown capability is actually added.

Expand Down
2 changes: 1 addition & 1 deletion .claude/hooks/enforce-writes-scope.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function resolveWriteTarget(p) {
// the Write tool cannot self-escalate by editing the gate's input.
const ALWAYS = [".pharn/**"];

// Fail-closed allow-list used when no scope file is set. pharn-cli's editable code (src/, tests/) +
// Fail-closed allow-list used when no scope file is set. pharn's editable code (src/, tests/) +
// the dev-loop's own build artifacts (.dev/features/) + the legacy root artifact zone (features/,
// retained, harmless) + process scratch (.pharn/, via ALWAYS). The sensitive zones (.dev/floor/,
// .dev/memory-bank/, .claude/, root spec docs, docs/, config) are intentionally absent — reaching
Expand Down
4 changes: 2 additions & 2 deletions .claude/hooks/enforce-writes-scope.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ function setter(cwd, ...args) {

// --- Hook, no scope file: fail-closed default-safe-set ---

test("no scope: src/ (pharn-cli source) is ALLOWED", () => {
test("no scope: src/ (pharn source) is ALLOWED", () => {
assert.equal(hook(tmp(), "src/lib/installer.ts").status, 0);
});

test("no scope: tests/ is ALLOWED", () => {
assert.equal(hook(tmp(), "tests/installer.test.ts").status, 0);
});

test("no scope: a pharn-oss module path (pharn-review/) is DENIED (pharn-cli has no module dirs — not in the safe-set)", () => {
test("no scope: a pharn-oss module path (pharn-review/) is DENIED (pharn has no module dirs — not in the safe-set)", () => {
assert.equal(hook(tmp(), "pharn-review/foo.md").status, 2);
});

Expand Down
4 changes: 2 additions & 2 deletions .dev/features/archetype-enum-align/PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

- spec_content_hash: bca940a5ad247c120e6d8a3acba119d0d8df51dca275964d0e54c48d729d3c4e # fix #4 (ARCHITECTURE.md)
- increment: Map DB signals (`.sql` files, `migrations/` dirs, and `prisma` / `@prisma/client` / `drizzle-orm` deps) to the existing `backend` archetype — the one residual after discovery found the enum alignment already complete. **Approved by the human at the halt (this run); knowingly reverses the tested decision #2 of increment #21.** (The enum↔pharn-oss alignment itself was already implemented across #17/#20/#21 — confirmed, no change needed.)
- layer(s): pharn-cli `src/lib` capability-resolver (ARCHITECTURE.md §5, "Archetype + map-consistency") — no `pharn-contracts` / `pharn-core` module files touched
- layer(s): pharn `src/lib` capability-resolver (ARCHITECTURE.md §5, "Archetype + map-consistency") — no `pharn-contracts` / `pharn-core` module files touched
- constitution_refs: [P6, P7, P5, P2, P3]

## Discovery finding — READ FIRST (the increment's premise is stale)

Everything the request describes as a *change* is **already in the tree** (verified by reads this run, not memory — P6). The task's premise — _"pharn-cli's archetype.ts currently uses {frontend, db, …} — mismatched"_ — is **false against live state**:
Everything the request describes as a *change* is **already in the tree** (verified by reads this run, not memory — P6). The task's premise — _"pharn's archetype.ts currently uses {frontend, db, …} — mismatched"_ — is **false against live state**:

| Requested change | Live state | Evidence |
| --- | --- | --- |
Expand Down
2 changes: 1 addition & 1 deletion .dev/features/archetype-file-tree-scan/PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ Signal → archetype mapping (the enum has no `db`/`frontend`, so names map onto
## Contracts satisfied

- **N/A — no `pharn-contracts` reference.** `pharn-contracts` is a PHARN-*product* layer (ARCHITECTURE.md
§4); this is a pharn-cli-internal `src/lib/` boundary and satisfies no product contract (as with #20).
§4); this is a pharn-internal `src/lib/` boundary and satisfies no product contract (as with #20).
- **Spec cited, not restated (P4):** ARCHITECTURE.md §5 (`archetype ∈ {ssr, backend, spa, lib}`, deterministic
detection) and §4 (the frameworkless `lib` base). This increment **extends the detection INPUT surface**
(adds file-tree signals) while preserving the enum and determinism; it does not restate the rule.
Expand Down
2 changes: 1 addition & 1 deletion .dev/features/archetype-io-boundary/PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ deliberately **out of scope** here (P7 — smallest coherent increment).
## Contracts satisfied

- **N/A — no `pharn-contracts` reference.** `pharn-contracts` is a PHARN-*product* layer (ARCHITECTURE.md
§4); this increment is a pharn-cli-internal `src/lib/` boundary and satisfies no product contract.
§4); this increment is a pharn-internal `src/lib/` boundary and satisfies no product contract.
- **Spec cited, not restated (P4):** ARCHITECTURE.md §5 (`archetype ∈ {ssr, backend, spa, lib}`, "detected
deterministically (membership over `package.json`)") and §4 (the frameworkless `lib` base). The new
boundary adds the I/O around that rule; it does not re-implement or restate the rule.
Expand Down
2 changes: 1 addition & 1 deletion .dev/features/archetype-missing-signal/PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ refactor, out of scope now (P7).

## Contracts satisfied

- **N/A — no `pharn-contracts` reference** (a pharn-cli-internal `src/lib/` boundary, as in the prior
- **N/A — no `pharn-contracts` reference** (a pharn-internal `src/lib/` boundary, as in the prior
increment).
- **Spec cited, not restated (P4):** ARCHITECTURE.md §5 (`archetype ∈ {ssr, backend, spa, lib}`,
"membership over `package.json`") and §4 (frameworkless `lib` base). The change only enriches the
Expand Down
2 changes: 1 addition & 1 deletion .dev/features/archetype-path-context/PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

- spec_content_hash: bca940a5ad247c120e6d8a3acba119d0d8df51dca275964d0e54c48d729d3c4e # fix #4 (ARCHITECTURE.md)
- increment: Give `classifyEntry` (detect-archetype.ts) the **path context** its four file-tree rules already assume in their comments — scope `api/`, `route.*`, `.sql`, and `.tsx/.jsx` matches to their documented locations so a file merely _named_ x no longer implies the project _has_ surface x; and (secondary) loosen `parseApplies` (capability-index.ts) to accept unquoted YAML `applies` tokens. No new archetype/enum member; determinism preserved.
- layer(s): pharn-cli `src/lib` — the archetype-detection **I/O boundary** (`detect-archetype.ts`) and the capability **fetch boundary** (`capability-index.ts`), both under ARCHITECTURE.md §5 "Archetype + map-consistency" / "Trust-fence". No `pharn-contracts` / `pharn-core` / `ARCHITECTURE.md` files touched (§5 is hook-protected + human-only).
- layer(s): pharn `src/lib` — the archetype-detection **I/O boundary** (`detect-archetype.ts`) and the capability **fetch boundary** (`capability-index.ts`), both under ARCHITECTURE.md §5 "Archetype + map-consistency" / "Trust-fence". No `pharn-contracts` / `pharn-core` / `ARCHITECTURE.md` files touched (§5 is hook-protected + human-only).
- constitution_refs: [P5, P2, P6, P7, P1, P3]

## Discovery findings — READ FIRST (grounded in reads this run, not memory — P6)
Expand Down
57 changes: 57 additions & 0 deletions .dev/features/canonical-npm-name/GRILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# GRILL — canonical-npm-name (advisory)

Plan under interrogation: `.dev/features/canonical-npm-name/PLAN.md`.
Spec-hash check: `sha256(ARCHITECTURE.md)` = `bca940a5ad247c120e6d8a3acba119d0d8df51dca275964d0e54c48d729d3c4e` — **matches** the plan's `spec_content_hash`. No spec drift (the binding block on drift is `/pharn-dev-build`'s floor-gate; here it only confirms).

> The PLAN is `trust: untrusted` to this griller. `problem`/`evidence` free-text below quotes the plan as DATA; the enum-gated fields (`type`/`rule_id`/`severity`/`file`) are this griller's own membership/path assertions. Grillers gate nothing — this whole log is advisory (fix #3).

## Findings

### Axis: testability (P1)

```yaml
- type: FINDING
rule_id: "P1"
severity: minor # advisory assignment — a griller never gates (fix #3)
file: ".dev/features/canonical-npm-name/PLAN.md:65"
problem: "The rename of the user-facing help/error copy in src/index.ts (USAGE) and src/steps/prereqs.ts is not pinned by any test, so a future edit could silently reintroduce the deprecated scoped name without a red gate."
evidence: "None required... the existing tests/index.test.ts --help assertion checks toContain('Usage:'), not the package-name string, so it stays green whether or not the USAGE string changes."
```

Note: this is a copy-only string change (no control-flow), so the miss is low-risk and P1 is arguably satisfied vacuously — but a one-line assertion (USAGE contains `pharn`, not `@pharn-dev/pharn`) would make the rename a *tested* fact for ~free. Surfaced for the human; not a gate.

### Axis: guarantee-audit / P0

```yaml
- type: FINDING
rule_id: "P0"
severity: minor # advisory assignment
file: ".dev/features/canonical-npm-name/PLAN.md:69"
problem: "The 'same file list as the scoped publish' guarantee is established by construction plus the local npm pack output, not by an actual list/byte diff against the already-published @pharn-dev/pharn@0.2.0 tarball (which is not fetched this run)."
evidence: "Published tarball is pharn-0.2.0.tgz, same file list as the scoped publish; content diffs = package.json.name + the bundled help/error strings in dist/index.js ... floor: npm pack --dry-run output."
```

Note: the floor that *does* hold deterministically is `npm pack --dry-run` → tarball name `pharn-0.2.0.tgz` + its file list (`package.json` + `dist/`). "Identical to the *scoped* publish" is a reasoning claim (only the name field + two bundled strings changed), honest to label as such rather than as a verified diff. Low-risk; the file SET is unchanged by construction (`files: ["dist"]`).

### Axis: documentation (P7) — no finding

The documentation griller's own rule: a **mechanical rename** may legitimately need no new docs, and this increment *is* the documentation update — README, SECURITY, `docs/**`, and CHANGELOG all move to the canonical name in-scope. The public surface (package name + install command) is documented, not shipped as self-explanatory. Declaration recognized → **no absence finding**.

### Axes with no findings

- **P2 (trust):** N/A — the increment ingests no untrusted artifact (no manifest/degit content); no taint introduced. Correctly stated in the plan.
- **P3 (one axis / no sibling imports):** every touched file changes for the single axis "canonical package name"; no command→command or step→step import is added.
- **P5 (determinism):** no new branch; the three open questions were resolved by asking the human at GATE 1 (terminal fallback = ask, honored).
- **P7 (scope):** real trigger (publish under the free canonical name); not speculative; one axis, not two bundled.

## Tooling observation (not a plan finding)

`node .dev/floor/count-grillers.mjs .` reported **81** registered grillers — but **all 81 are under `test-*/` install fixtures** (`test-backend/pharn/...`, `test-full/pharn/...`, etc.), i.e. copies PHARN installed into this CLI's own test apps, not this repo's dev-loop grillers. The counter does not exclude the local test-app dirs, so it over-reports. This does not affect this increment (it is a dev-loop tooling quirk, not a defect in the plan), but the same over-count likely appears in `count-verifiers.mjs` at `/pharn-dev-verify` — noted so it is expected there. Recorded as prose (no `PLAN.md:line` to cite → not a finding-shape object).

## Summary

The plan is a tightly-scoped, single-axis mechanical rename that also updates all of its own user-facing documentation. The guarantee audit reduces its real claims to the floor (`npm pack`, `npm run check`) and labels the rest advisory; the trust surface is untouched; the three live-state contradictions (phantom `--wizard`, `provenance` mis-description, CHANGELOG layout) were surfaced and human-resolved before build. The only concerns are two **minor, advisory** ones: (1) the src copy rename is not pinned by a test, and (2) "identical to the scoped publish" is a reasoning claim, not a fetched-tarball diff. Neither blocks build.

## Verdict

ADVISORY VERDICT: 2 concerns raised (0 blocking-severity, 2 minor/advisory) — for the human to weigh before `/pharn-dev-build`. This grill did NOT "pass" the plan and guarantees nothing; it surfaces the above. The only deterministic backstops remain `/pharn-dev-build`'s floor-gates (spec-hash, unresolved HALT questions) and `.dev/floor/validate.mjs`.
Loading