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
83 changes: 83 additions & 0 deletions .dev/features/f8-package-private/GRILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# GRILL — f8-package-private

Plan under interrogation: `.dev/features/f8-package-private/PLAN.md`.

**Spec-hash check:** recomputed `sha256(pharn/ARCHITECTURE.md)` =
`8f5ec002e3b18cbfd2f094b08a3671f7ed42a05a3fbaf01a11bbbd28da30fb52`, matches the plan's
`spec_content_hash` exactly. No drift.

**Griller membership (floor, `pharn/floor/count-grillers.mjs`):** 13 registered
(`a11y, architecture, comprehension, coupling, documentation, error-handling, i18n, migrations,
observability, performance, privacy, security, testability`). All 13 applied below; this is advisory
end-to-end (fix #3) — nothing here gates `/pharn-dev-build`.

## Findings

```yaml
- type: FINDING
rule_id: P1
severity: important
file: ".dev/features/f8-package-private/PLAN.md:1"
problem: "The plan declares no verification/acceptance approach for the change it makes — the '## Evals to write (P1)' section correctly says 'None' because package.json is not a Capability, but that answers a different question than 'how do we know the fix worked.'"
evidence: "## Evals to write (P1)\n\n- None — P1 (\"no Capability ships without evals\") governs `role:`-bearing Capabilities under `pharn/`. `package.json` carries no `role:` frontmatter and is not a Capability, so P1 does not apply to this increment."
```

```yaml
- type: FINDING
rule_id: P0
severity: minor
file: ".dev/features/f8-package-private/PLAN.md:24"
problem: 'The guarantee audit correctly labels the npm-refusal behavior advisory (no PHARN floor primitive backs it), but does not name that this leaves no regression guard: a future edit could silently drop "private": true and nothing in `npm run check` would catch it.'
evidence: '"A real `npm publish` refuses once `private: true` is set" -> advisory (external system behavior). ... no PHARN-side hook, hash, or enum check enforces it.'
```

```yaml
- type: FINDING
rule_id: P3
severity: minor
file: ".dev/features/f8-package-private/PLAN.md:19"
problem: 'The single ''## Files'' entry bundles two edits to package.json — adding "private": true (a publish-safety fix) and deleting the dead "main" field (a stale-reference cleanup) — under one stated axis; worth the human''s explicit confirmation these are one reason to change, not two glued together.'
evidence: '- package.json — add "private": true after "version"; delete the "main": "index.js" line — layer repo-meta'
Comment on lines +17 to +40

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Use exact line anchors in every review artifact.

Both reports point findings at unrelated lines, which makes the recorded issues non-actionable.

  • .dev/features/f8-package-private/GRILL.md#L17-L40: update P1, P0, and P3 to the exact PLAN.md evidence ranges.
  • .dev/features/f8-package-private/REVIEW.md#L49-L55: replace package.json:1 with the changed package.json ranges.
📍 Affects 2 files
  • .dev/features/f8-package-private/GRILL.md#L17-L40 (this comment)
  • .dev/features/f8-package-private/REVIEW.md#L49-L55
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dev/features/f8-package-private/GRILL.md around lines 17 - 40, Update the
P1, P0, and P3 findings in .dev/features/f8-package-private/GRILL.md#L17-L40 to
use exact line anchors for the corresponding evidence ranges in PLAN.md rather
than unrelated lines. In .dev/features/f8-package-private/REVIEW.md#L49-L55,
replace package.json:1 with the exact changed package.json ranges. Preserve each
finding’s existing scope and content while making all references actionable.

```

```yaml
- type: FINDING
rule_id: P2
severity: minor
file: ".dev/features/f8-package-private/PLAN.md:1"
problem: "The originating defect narrative frames this as preventing the repo from being 'shipped' via publish, which could read as a confidentiality fix; the repo is already public on GitHub, so the actual value of `private: true` is preventing npm-registry namespace confusion with the real `@pharn-dev/pharn` package, not secret exposure — worth precise phrasing in the commit message / CHANGELOG note."
evidence: '"A single `npm publish` would push the entire working tree -- .dev/, pharn/, .claude/, everything -- to the registry under that name."'
```

## Non-findings (checked, no concern)

- **Documentation griller (P7):** no public/exported surface is added (`private`/`main` are npm-standard
package.json fields, not a new API or config key a downstream consumer reads) — genuinely needs no
dedicated documentation. Advisory-only observation: given this repo's own exhaustive CHANGELOG habit
(see the `[Unreleased]` F9 entry), the optional one-line note the plan allows is worth taking even
though not required.
- **Architecture griller (P3, Layer 2 fit):** correctly scoped outside the `pharn/` capability tree as
repo-meta; no architectural-fit concern.
- **Security griller (Layer 1, floor secret-literal scan):** no hardcoded secret or credential literal
in the plan text — clean.
- **Testability griller (Layer 2 adequacy):** N/A — Layer 1 already raised absence above; adequacy is
moot until a verification approach exists.
- **a11y, coupling, comprehension, error-handling, i18n, migrations, observability, performance,
privacy:** not applicable — no UI, no runtime code path, no cross-module coupling, no error-handling
surface, no user-facing text, no data migration, no metrics/logging surface, no perf-sensitive path,
no personal data. One JSON config file, two fields, zero behavior.

## Summary

The plan is small and well-scoped, and the spec→plan hash chain holds. The two live findings worth the
human's attention before build: (1) the plan doesn't declare how the fix will be verified beyond "re-run
the reproduce" implied by context — the build/verify stages will in practice confirm it via
`npm run check` + the plan's own verification checklist from the originating request, but that checklist
never made it into `PLAN.md`'s structure; (2) there is no durability guard against a future silent
regression of `private: true` — named here as a residual, not a recommendation to build a checker now
(P7: no trigger from a real dogfood/eval failure exists yet, the same reasoning `product-capability-catalog`
used to defer its own follow-up). The P3 bundling and P2 risk-framing notes are precision nits, not
blockers.

**ADVISORY VERDICT: 4 concerns raised (0 blocking-severity, 1 important, 3 minor) — for the human to
weigh before `/pharn-dev-build`. This is not a pass/fail gate; `/pharn-dev-grill` blocks nothing.**
34 changes: 34 additions & 0 deletions .dev/features/f8-package-private/PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# PLAN — f8-package-private

- spec_content_hash: 8f5ec002e3b18cbfd2f094b08a3671f7ed42a05a3fbaf01a11bbbd28da30fb52
- applied_lessons: [L8, L19]
- increment: Add `"private": true` and remove the dead `"main": "index.js"` field from `package.json` so a real `npm publish` refuses instead of shipping the whole repo.
- layer(s): repo-meta (not a `pharn/` capability layer — `package.json` sits outside `pharn-contracts` / `pharn-core` / `pharn-pipeline` / `pharn-review`)
- constitution_refs: [P6, P7]

## Applied lessons

- L8 — This increment's sole output is one file (`package.json`); the writes-scope for `/pharn-dev-build` will resolve to that single `--target`, matching L8's "favor single-file command outputs" guidance directly (no multi-artifact placeholder to lose scope on).
- L19 — Any format/lint command run over this change during build or this plan's own artifact-formatting step must be scoped to the specific written file (`npx prettier --write package.json`, `npx prettier --write .dev/features/f8-package-private/PLAN.md`), never a repo-wide `npm run format`, so no unrelated file is silently swept into this increment's diff.

## Files

- `package.json` — add `"private": true` after `"version"`; delete the `"main": "index.js"` line — layer repo-meta

## Contracts satisfied

- None — `package.json` is not a `pharn-contracts` schema, a Capability, or a rule/lens/griller. This is a repo-meta correction outside the capability tree, so no `pharn-contracts` entry applies (CLAUDE.md, "Repo layout — the dev/product boundary").

## Evals to write (P1)

- None — P1 ("no Capability ships without evals") governs `role:`-bearing Capabilities under `pharn/`. `package.json` carries no `role:` frontmatter and is not a Capability, so P1 does not apply to this increment.

## Guarantee audit (P0)

- "A real `npm publish` refuses once `private: true` is set" → **advisory (external system behavior)**. This is npm's own documented behavior, not a reduction to one of PHARN's three floor primitives (hook / content-hash / enum-regex) — no PHARN-side hook, hash, or enum check enforces it. It is stated as an observable npm behavior, never labeled a PHARN guarantee.
- "`package.json` still parses and is prettier-clean after the edit" → **floor-adjacent, enforced by the existing gate**: `npm run format:check` (part of `npm run check`) already runs `prettier --check .` over the whole repo, so a malformed or unformatted `package.json` fails that pre-existing gate. No new floor primitive is added by this increment.
- "This edit does not alter the product surface" → **enum/regex-reducible, by inspection**: `package.json` is not in CLAUDE.md's bump-triggering set (the `pharn/` capability tree, `pharn/floor/*.mjs`, the four trusted docs, the product `.claude/` surface) — it is named explicitly under "Pure repo-meta ... does not bump either." No `SKILLS_VERSION` bump, no floor check needed to prove it (the claim rests on the already-published, human-authored enumeration in CLAUDE.md, not on a new mechanism this increment invents).
Comment on lines +26 to +30

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- PLAN ---'
sed -n '1,90p' .dev/features/f8-package-private/PLAN.md
printf '%s\n' '--- CLAUDE bump rules ---'
rg -n -A12 -B8 'bump|trigger|Pure repo-meta|SKILLS_VERSION|package\.json' CLAUDE.md
printf '%s\n' '--- floor files ---'
git ls-files 'pharn/floor/*.mjs'

Repository: pharn-dev/pharn-oss

Length of output: 18719


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- bump-related enforcement ---'
rg -n -i -A5 -B5 'SKILLS_VERSION|bump-triggering|product surface|package\.json' .dev pharn .claude package.json CLAUDE.md \
  | head -n 240
printf '%s\n' '--- plan lines ---'
nl -ba .dev/features/f8-package-private/PLAN.md | sed -n '22,34p'
printf '%s\n' '--- package metadata ---'
cat package.json
printf '%s\n' '--- relevant scripts ---'
node - <<'JS'
const fs = require('fs');
const p = JSON.parse(fs.readFileSync('package.json', 'utf8'));
console.log(JSON.stringify(p.scripts ?? {}, null, 2));
JS

Repository: pharn-dev/pharn-oss

Length of output: 25452


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- feature files ---'
git ls-files '.dev/features/f8-package-private/*'
printf '%s\n' '--- feature objectives and verification references ---'
rg -n -i -A4 -B4 'objective|verification|verify|publish|private|bump|checklist' .dev/features/f8-package-private
printf '%s\n' '--- deterministic wording and checker references ---'
python3 - <<'PY'
from pathlib import Path
import re

plan = Path(".dev/features/f8-package-private/PLAN.md").read_text()
claude = Path("CLAUDE.md").read_text()
floor = "\n".join(
    p.read_text()
    for p in Path("pharn/floor").glob("*.mjs")
    if not p.name.endswith(".test.mjs")
)

print("plan says enum/regex-reducible:",
      bool(re.search(r"enum/regex-reducible", plan)))
print("plan says no floor primitive:",
      bool(re.search(r"no floor check needed|no .*floor primitive", plan, re.I)))
print("CLAUDE explicitly excludes package.json:",
      bool(re.search(r"package\.json\s*/?\s*`?\s*/?\s*SKILLS_VERSION itself", claude)))
print("product-set sentence includes package.json:",
      bool(re.search(r"package\.json", claude[claude.find("The bump-triggering set"):claude.find("The bump-triggering set") + 800])))
print("product floor contains SKILLS_VERSION bump logic:",
      bool(re.search(r"SKILLS_VERSION|bump-triggering|package\.json", floor, re.I)))
PY

Repository: pharn-dev/pharn-oss

Length of output: 30680


Mark the no-bump conclusion as advisory.

CLAUDE.md explicitly excludes package.json from the bump-triggering set, but no floor checker enforces that set. A manual comparison is not an enum/regex check. Replace enum/regex-reducible, by inspection with advisory wording and add the package-specific verification checklist to PLAN.md.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dev/features/f8-package-private/PLAN.md around lines 26 - 30, The “This
edit does not alter the product surface” conclusion in the Guarantee audit is
incorrectly labeled enum/regex-reducible; change it to advisory wording because
the package exclusion is not enforced by a floor checker. In PLAN.md, add the
package-specific verification checklist requested by the comment, while
preserving the existing CLAUDE.md enumeration reference and no-bump conclusion.

Source: Coding guidelines


## Open questions (HALT)

- None. The defect is reproduced live (see plan args), the fix is a two-field JSON edit with no ambiguity, and CLAUDE.md is dispositive on the no-bump question.
Comment on lines +22 to +34

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the acceptance checks to the plan.

## Evals to write (P1) only explains why Capability evals do not apply. It does not record the acceptance checks listed in the PR objectives: package-field checks, npm publish --dry-run, CI checks, and feature-audit validation. Add the commands, expected results, and scope in a verification section. Keep external npm behavior advisory.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.dev/features/f8-package-private/PLAN.md around lines 22 - 34, Expand
.dev/features/f8-package-private/PLAN.md with a verification section documenting
acceptance checks for package fields, npm publish --dry-run, CI, and
feature-audit validation, including each command, expected result, and scope.
Keep npm’s refusal of publishing private packages explicitly advisory, and
retain the existing P1 and P0 audit conclusions.

39 changes: 39 additions & 0 deletions .dev/features/f8-package-private/REGRESSION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# REGRESSION — f8-package-private

**Base:** `HEAD` (working-tree dogfood — `git status --porcelain` was non-empty, so base = HEAD per
the deterministic auto-detect rule).

## Partition

- **Inside (changed scope):** `.dev/features/f8-package-private/GRILL.md`,
`.dev/features/f8-package-private/PLAN.md`, `package.json`
- **Declared (`## Files` in the approved plan):** `package.json`
- **Escaped:** none
- **Escape-exempt (this feature's own stage artifacts, per `--feature`):**
`.dev/features/f8-package-private/GRILL.md`, `.dev/features/f8-package-private/PLAN.md`
- **Style-gate skip:** applied — `inside` touches no shared style config
(`eslint.config.mjs` / `.prettierrc.json` / `.prettierignore` / `.markdownlint-cli2.jsonc`), so
`lint` / `format:check` / `lint:md` are provably unable to flip outside the feature and were skipped
at both base and head.

## Outside gates run (base → head)

| gate | base | head |
| ------------------------------------------------------------------------------------------ | ---- | ---- |
| `tests` (63 outside `*.test.mjs`/`*.test.cjs` files) | 0 | 0 |
| `validate` (`pharn/floor/validate.mjs .`) | 0 | 0 |
| `structural:pharn/pharn-review/trust-fence/evals/expected/expected-injection-comment.json` | 0 | 0 |

## Regressions

None.

## Pre-existing failures

None.

**REGRESSIONS: none — no deterministically-detectable breakage outside the feature.**

This certifies only the comparison: every gate this suite runs was green at the pre-build baseline and
stays green at HEAD. It does not certify the feature itself is correct or complete — it catches exactly
what the deterministic suite covers, nothing more (P0).
84 changes: 84 additions & 0 deletions .dev/features/f8-package-private/REVIEW.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# REVIEW — f8-package-private

**Floor first (P0):** `node pharn/floor/validate.mjs .` → `FLOOR: GREEN — 36 capabilities checked in .`
(exit 0). The increment reached review on a green floor.

**Diff under review** (`git diff HEAD -- package.json`): adds `"private": true` after `"version"`;
removes the `"main": "index.js"` line. Nothing else changed. The increment is `trust: untrusted` per
the loaded prefix; no instruction-looking content was found in the diff (it is two JSON key edits, no
comments, no strings a model could be steered by).

## L-floor → P0

Re-checked the plan's guarantee audit against what actually landed:

- "A real `npm publish` refuses once `private: true` is set" — labeled `advisory` (external npm
behavior, no PHARN floor primitive). Correct label; `private: true` is now live in `package.json`,
confirmed by direct read (`require('./package.json').private === true`).
- "`package.json` still parses and is prettier-clean" — floor-adjacent via the pre-existing
`format:check` gate, re-confirmed GREEN at `/pharn-dev-verify` (after a whitespace-only reformat of
`regression-report.json`, unrelated to this file — see `VERIFY.md`).
- "No `SKILLS_VERSION` bump" — enum/regex-reducible by inspection against CLAUDE.md's bump-triggering
set; `package.json` is explicitly named as pure repo-meta. `SKILLS_VERSION` file is untouched
(confirmed: still `2.5.1`).

No blocking finding. No guarantee is claimed here without a floor reduction or an `advisory` label.

## L-eval → P1

`package.json` carries no `role:` frontmatter and is not a Capability; P1 ("no Capability ships without
evals") does not apply. No `enforces` / `rule_id` binding is introduced. Nothing to check — no finding.

## L-trust → P2

No untrusted artifact is ingested by this increment's own content. The reviewed diff contains no
free-text finding output of its own to fence. No finding.

## L-axis → P3

One file changed (`package.json`), no sibling module reference, no `pharn-contracts` bypass. The two
edits (`add private` / `remove dead main`) were flagged at `/pharn-dev-grill` as a possible axis-bundling
concern (`GRILL.md`, `rule_id: P3`, severity minor) — re-examined here: both edits serve the single
stated axis ("`package.json` currently presents this repo as publishable/importable when it is
neither"), and splitting them into two PRs would produce no independent value (the `main` removal has no
meaning without the `private` context that explains why it's dead, and vice versa). Not elevated to
blocking; recorded as **advisory, minor** — same severity as the grill finding.

## Findings

```yaml
- type: FINDING
rule_id: P3
severity: minor
file: "package.json:1"
problem: "Two edits (add 'private', remove dead 'main') are bundled under one plan axis; defensible but worth naming explicitly in the PR description rather than left implicit."
evidence: 'diff: +"private": true (line 4); -"main": "index.js" (line 26, pre-edit)'
```

**Gate:** advisory-gate (warn) — not a floor-detectable sibling reference, rests on judgment of what
counts as "one axis." Does not block.

## Verdict

**GREEN — 0 blocking floor-gate findings, 1 minor advisory-gate finding.** The increment is done: floor
GREEN, regress clean (`regression-report.json`: `no-regressions`), verify PASS
(`verify-report.json`: `PASS`, 0 verifiers registered), review raises no blocker.

## Proposed lesson candidate (NOT promoted here — human-gated `/pharn-dev-memory-promote` only)

**Candidate:** A `/pharn-dev-plan` for a non-Capability repo-meta fix can satisfy `check-plan-lessons.mjs`
and the P1 eval-coverage question ("None — not a Capability") while still omitting a plain verification
checklist — "how do we confirm the fix worked" — because no floor check requires one outside the
testability griller's advisory Layer-1 presence check. `/pharn-dev-grill`'s testability lens caught the gap
in this run (`GRILL.md`, `rule_id: P1`, severity important) on `.dev/features/f8-package-private/PLAN.md`,
which had no declared verification section despite the originating request including an explicit
checklist that never made it into the plan's structure. The gap was harmless here — `/pharn-dev-build` and
`/pharn-dev-verify` independently confirmed the fix live and via the deterministic gate set — but a plan for
a more complex non-Capability change could omit verification with no downstream stage catching it before
review.

**Provenance:** feature `f8-package-private`; surfaced by `.dev/features/f8-package-private/GRILL.md`
(testability griller finding, this run); commit `unknown` (uncommitted at review time).

**Not promoted:** single occurrence, not yet a recurring pattern (P7 — a real trigger exists, but
promotion is the human's call at a separate, gated `/pharn-dev-memory-promote` run).
44 changes: 44 additions & 0 deletions .dev/features/f8-package-private/SHIP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# SHIP — f8-package-private

Gated `/pharn-dev-ship` run over the increment "add `\"private\": true`, remove the dead `\"main\": \"index.js\"`
field from `package.json`" (F8).

## Stages run, in order

1. `/pharn-dev-plan` → `.dev/features/f8-package-private/PLAN.md` → **GATE 1: approved as written** (human).
2. `/pharn-dev-grill` → `.dev/features/f8-package-private/GRILL.md` → advisory, 4 concerns (0 blocking, 1
important, 3 minor) — gates nothing, proceeded.
3. `/pharn-dev-build` → `package.json` edited (2 fields) → `pharn/floor/validate.mjs .` exit **0**
(`FLOOR: GREEN — 36 capabilities checked in .`).
4. `/pharn-dev-regress` → `.dev/features/f8-package-private/regression-report.json` /
`REGRESSION.md` → `.verdict` = **`no-regressions`**.
5. `/pharn-dev-verify` → `.dev/features/f8-package-private/verify-report.json` / `VERIFY.md` → `.verdict` =
**`PASS`** (`test`, `validate`, `lint`, `format:check`, `lint:md`,
`structural:pharn/pharn-review/trust-fence/evals/expected/expected-injection-comment.json` — all exit 0; 0
verifiers registered).
6. `/pharn-dev-review` → `.dev/features/f8-package-private/REVIEW.md` → **GREEN**, 0 blocking floor-gate
findings, 1 minor advisory-gate finding (P3, axis-bundling — examined and not elevated); one lesson
candidate proposed (not promoted — requires a separate gated `/pharn-dev-memory-promote` run).

**Where the run ended:** reached the end of the chain (`/pharn-dev-review` complete) — **this is GATE 2.**

## Structural verdicts, verbatim

| stage | verdict source | value |
| -------------------- | -------------------------------------------------------------------- | ---------------- |
| `/pharn-dev-build` | `pharn/floor/validate.mjs .` exit code | `0` (GREEN) |
| `/pharn-dev-regress` | `.dev/features/f8-package-private/regression-report.json` `.verdict` | `no-regressions` |
| `/pharn-dev-verify` | `.dev/features/f8-package-private/verify-report.json` `.verdict` | `PASS` |

## Pointers (not restated — P4)

- `.dev/features/f8-package-private/GRILL.md` — advisory grill-log (4 findings: P1 important, P0/P3/P2
minor).
- `.dev/features/f8-package-private/REVIEW.md` — 4-lens review + 1 proposed (unpromoted) lesson
candidate.

## Standing decision

The chain ran; the named floor verdicts are as shown above. **This is NOT a judgment that the increment
is good or wise** — that is the human's call at this post-review gate (merge / fix / abandon). No
merge, push, or `PHARN ✓ reviewed` seal was applied by this run.
Loading