persona-harness 0.8.21 → 0.8.23

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.
@@ -9,13 +9,21 @@ version/package chronology, use
9
9
  [`docs/releases/README.md`](../../releases/README.md) and
10
10
  [`docs/releases/package-index.md`](../../releases/package-index.md).
11
11
 
12
- ## Current 0.8.21 Package Authority
12
+ ## Current 0.8.23 Package Authority
13
13
 
14
- The current unpublished package authority is 0.8.21. Its root package,
15
- lockfile, private shared-skills package, and v0821 acceptance record must agree
16
- exactly. The published 0.8.20 release is immutable historical evidence only
14
+ The current unpublished package authority is 0.8.23. Its root package,
15
+ lockfile, private shared-skills package, and v0823 acceptance record must agree
16
+ exactly. The published 0.8.22 release is immutable historical evidence only
17
17
  and must not be retagged, rerun, or published.
18
- The package-visible read-only `ph authority verify` surface never fetches,
18
+
19
+ The package tarball contains exactly one root README candidate, `README.md`,
20
+ so npm presents the current English first screen and 30-second demo
21
+ deterministically. Korean, Japanese, and Simplified Chinese source documents
22
+ remain under `docs/current/` and are linked from the English README through
23
+ their GitHub source URLs.
24
+ The package-visible read-only `ph authority verify` surface accepts canonical
25
+ `sha256:<64hex>` or an exact raw SHA-256 hex digest, normalizing either form
26
+ before the same no-follow archive boundary. It never fetches,
19
27
  persists, consumes, finishes, or replays authority. Its `.2` result exposes a
20
28
  finite `sourceReason` only alongside `source-mismatch`; unavailable Sigstore
21
29
  trust remains a fixed blocked result rather than a trust claim.
@@ -92,7 +92,7 @@ caller that already holds one original archive:
92
92
  ```text
93
93
  ph authority verify [owner/repository] --archive <original-archive> \
94
94
  --artifact-id <id> --run-id <run-id> --source-head <commit> \
95
- --artifact-digest sha256:<digest> --json
95
+ --artifact-digest <sha256:<digest>|64hex> --json
96
96
  ```
97
97
 
98
98
  The command requires all four tuple fields, the current enrolled source and
@@ -102,6 +102,10 @@ and checks its digest before invoking the existing verifier. It never reads a
102
102
  GitHub credential, fetches an artifact, writes the authority store, consumes
103
103
  authority, runs Finish, or performs replay.
104
104
 
105
+ The digest is canonicalized to lowercase `sha256:<64hex>`. Callers may supply
106
+ that canonical form or an exact raw 64-character SHA-256 hex digest; every
107
+ other form remains blocked before archive verification.
108
+
105
109
  Its public result is `consumer-authority-verify.2` with fixed fields for
106
110
  eligibility, consumption state, bounded reason, schema, source-fallback state,
107
111
  and terminal state. Only `source-mismatch` includes a finite nonreflective
@@ -1,12 +1,11 @@
1
1
  # v0.8.21 Release Notes
2
2
 
3
- ## Current package authority
3
+ ## Historical package authority
4
4
 
5
- `0.8.21` is the current unpublished package authority. The root package,
5
+ `0.8.21` was published as an immutable stable release. Its root package,
6
6
  lockfile, private shared-skills package, and
7
- `consumer-authority-v0821-acceptance.json` bind the same version. Published
8
- `0.8.20` is immutable historical evidence and cannot authorize this candidate
9
- or a replacement publish.
7
+ `consumer-authority-v0821-acceptance.json` remain historical release evidence;
8
+ they cannot authorize a later candidate or a second publish.
10
9
 
11
10
  ## Portable repair source identity
12
11
 
@@ -22,9 +21,8 @@ The exclusion is intentionally narrow. A reviewed
22
21
  all other tracked or untracked source stay in the signed identity and continue
23
22
  to drift or fail closed as before.
24
23
 
25
- ## Release boundary
24
+ ## Historical boundary
26
25
 
27
- Fresh Source and Package gates must bind the exact `0.8.21` candidate and its
28
- canonical tar before protected integration, stable Release, and one npm
29
- `latest` publication. A released successor package is the lawful fixture-pin
30
- trigger for #338; fixture and V4 observations remain separately governed.
26
+ The release completed through protected integration, a stable GitHub Release,
27
+ and one npm `latest` publication. Fixture and V4 observations remain separate
28
+ evidence paths and do not alter this immutable release history.
@@ -0,0 +1,27 @@
1
+ # v0.8.22 Release Notes
2
+
3
+ ## Historical package authority
4
+
5
+ `0.8.22` was prepared with a root package, lockfile, private shared-skills
6
+ package, and `consumer-authority-v0822-acceptance.json` bound to the same
7
+ version. It is now immutable published history. The current source candidate
8
+ is `0.8.23`; this record cannot authorize a replacement publish.
9
+
10
+ ## Authority verify digest normalization
11
+
12
+ The installed read-only `ph authority verify` command accepts either its
13
+ canonical `sha256:<64hex>` archive digest or an exact raw 64-character
14
+ SHA-256 hex value. Raw input is normalized before archive comparison, so both
15
+ forms bind the same tuple and retain the existing no-follow, enrollment,
16
+ source, crypto, and non-consuming boundaries.
17
+
18
+ Partial tuples, invalid sizes or characters, unsupported algorithms, duplicate
19
+ flags, symlink archives, and tuple mismatches still block before verifier,
20
+ store, fetch, Finish, or replay.
21
+
22
+ ## Release boundary
23
+
24
+ The historical candidate required fresh Source and Package gates to bind its
25
+ canonical tar before protected integration, stable Release, and one npm
26
+ `latest` publication. Subsequent release candidates require their own current
27
+ version authority and independent evidence.
@@ -0,0 +1,25 @@
1
+ # v0.8.23 Release Notes
2
+
3
+ ## Current package authority
4
+
5
+ `0.8.23` is the current unpublished package authority. The root package,
6
+ lockfile, private shared-skills package, and
7
+ `consumer-authority-v0823-acceptance.json` bind the same version. Published
8
+ `0.8.22` is immutable historical evidence and cannot authorize this candidate
9
+ or a replacement publish.
10
+
11
+ ## Deterministic npm landing README
12
+
13
+ The package tarball contains exactly one root README candidate, `README.md`,
14
+ so npm's package landing page uses the current English first screen and
15
+ 30-second demo. Korean, Japanese, and Simplified Chinese source documents
16
+ remain in `docs/current/`; the English README links to their GitHub source
17
+ paths. This changes presentation selection only and makes no claim about
18
+ translation quality.
19
+
20
+ ## Release boundary
21
+
22
+ Fresh Source and Package gates must bind the exact `0.8.23` candidate and its
23
+ canonical tar before protected integration, stable Release, and one npm
24
+ `latest` publication. Registry readback must report `readmeFilename` as
25
+ `README.md` and retain the candidate's canonical tar identity.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "persona-harness",
3
- "version": "0.8.21",
3
+ "version": "0.8.23",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.8.2",
@@ -21,9 +21,6 @@
21
21
  "dist",
22
22
  "LICENSE",
23
23
  "README.md",
24
- "README.ko.md",
25
- "README.ja.md",
26
- "README.zh-cn.md",
27
24
  "CHANGELOG.md",
28
25
  "img",
29
26
  ".persona/harness.jsonc",
@@ -248,6 +245,10 @@
248
245
  "scripts/consumer-authority-v0820-acceptance-schema.mjs",
249
246
  "scripts/consumer-authority-v0821-acceptance-schema.d.mts",
250
247
  "scripts/consumer-authority-v0821-acceptance-schema.mjs",
248
+ "scripts/consumer-authority-v0822-acceptance-schema.d.mts",
249
+ "scripts/consumer-authority-v0822-acceptance-schema.mjs",
250
+ "scripts/consumer-authority-v0823-acceptance-schema.d.mts",
251
+ "scripts/consumer-authority-v0823-acceptance-schema.mjs",
251
252
  "scripts/consumer-authority-v081-acceptance-schema.d.mts",
252
253
  "scripts/consumer-authority-v081-acceptance-schema.mjs",
253
254
  "scripts/consumer-authority-rc1-acceptance-schema.mjs",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@persona-harness/shared-skills",
3
- "version": "0.8.21",
3
+ "version": "0.8.23",
4
4
  "type": "module",
5
5
  "private": true,
6
6
  "description": "Persona-owned portable skill procedures and optional overlays",
@@ -0,0 +1,40 @@
1
+ export const V0822_ACCEPTANCE_SCHEMA_VERSION: "consumer-authority-v0822-acceptance.1"
2
+
3
+ export class V0822AcceptanceManifestError extends Error {
4
+ readonly code: "v0822-acceptance-schema"
5
+ }
6
+
7
+ export type V0822AcceptanceManifest = Readonly<Record<string, unknown>> & Readonly<{
8
+ readonly authority: Readonly<{
9
+ readonly readOnlyVerify: Readonly<{
10
+ readonly archiveInput: Readonly<{
11
+ readonly ancestorDirectoryChurn: string
12
+ readonly arbitrarySymlinkAncestorOrLeaf: string
13
+ readonly darwinSystemTemporaryAlias: string
14
+ readonly directParentIntegrity: string
15
+ readonly nonDarwin: string
16
+ }>
17
+ readonly artifactDigestInput: string
18
+ readonly command: string
19
+ readonly noCredentialFetchStoreConsumeFinishReplay: boolean
20
+ readonly schemaVersion: string
21
+ }>
22
+ }>
23
+ readonly package: Readonly<{
24
+ readonly channel: string
25
+ readonly scope: string
26
+ readonly version: string
27
+ }>
28
+ readonly initialization: Readonly<{
29
+ readonly packageTemplateIdentity: string
30
+ readonly repairStaging: string
31
+ }>
32
+ readonly projectFinishSourceIdentity: Readonly<{
33
+ readonly adoptedInstructionPolicy: string
34
+ readonly repairInferenceObservations: string
35
+ }>
36
+ }>
37
+
38
+ export function canonicalV0822AcceptanceManifest(): V0822AcceptanceManifest
39
+ export function readV0822AcceptanceManifest(packageRoot: string): V0822AcceptanceManifest
40
+ export function parseV0822AcceptanceManifest(value: unknown, packageVersion: string): V0822AcceptanceManifest
@@ -0,0 +1,83 @@
1
+ import { readFileSync } from "node:fs"
2
+ import { join } from "node:path"
3
+ import { isDeepStrictEqual } from "node:util"
4
+
5
+ import { canonicalV0821AcceptanceManifest } from "./consumer-authority-v0821-acceptance-schema.mjs"
6
+ import { parseCanonicalPackagePublisherPlan } from "./canonical-package-publisher.mjs"
7
+ import { parseExternalArtifactTransportPlan } from "./consumer-authority-external-artifact-transport-plan.mjs"
8
+ import { parseExternalAttestationCommandPlan } from "./consumer-authority-external-attestation-command-plan.mjs"
9
+ import { parseObserverGhToolContract } from "./consumer-authority-observer-gh-tool.mjs"
10
+
11
+ export const V0822_ACCEPTANCE_SCHEMA_VERSION = "consumer-authority-v0822-acceptance.1"
12
+
13
+ const V0822_PACKAGE_VERSION = "0.8.22"
14
+ const ACCEPTANCE_PATH = join("docs", "current", "release", "consumer-authority-v0822-acceptance.json")
15
+ const EXPECTED_MANIFEST = buildExpectedManifest()
16
+
17
+ export class V0822AcceptanceManifestError extends Error {
18
+ constructor(code) {
19
+ super(code)
20
+ this.code = code
21
+ }
22
+ }
23
+
24
+ export function canonicalV0822AcceptanceManifest() {
25
+ return structuredClone(EXPECTED_MANIFEST)
26
+ }
27
+
28
+ export function readV0822AcceptanceManifest(packageRoot) {
29
+ let packageVersion
30
+ let value
31
+ try {
32
+ packageVersion = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8")).version
33
+ value = JSON.parse(readFileSync(join(packageRoot, ACCEPTANCE_PATH), "utf8"))
34
+ } catch {
35
+ fail()
36
+ }
37
+ return parseV0822AcceptanceManifest(value, packageVersion)
38
+ }
39
+
40
+ export function parseV0822AcceptanceManifest(value, packageVersion) {
41
+ if (packageVersion !== V0822_PACKAGE_VERSION || !isDeepStrictEqual(value, EXPECTED_MANIFEST)) fail()
42
+ parseCanonicalPackagePublisherPlan(value.canonicalPackagePublisherPlan)
43
+ parseExternalAttestationCommandPlan(value.externalAttestationCommandPlan)
44
+ parseExternalArtifactTransportPlan(value.externalArtifactTransportPlan)
45
+ parseObserverGhToolContract(value.observerGhTool)
46
+ return value
47
+ }
48
+
49
+ function buildExpectedManifest() {
50
+ const manifest = canonicalV0821AcceptanceManifest()
51
+ manifest.schemaVersion = V0822_ACCEPTANCE_SCHEMA_VERSION
52
+ manifest.package.channel = "unpublished"
53
+ manifest.package.scope = "source-candidate"
54
+ manifest.package.version = V0822_PACKAGE_VERSION
55
+ delete manifest.v0820HistoricalRelease
56
+ manifest.v0821HistoricalRelease = {
57
+ outcome: "published-0.8.21-release-is-immutable-and-not-reusable-for-this-unpublished-v0822-source-candidate-or-any-later-package",
58
+ reusableForV0822: false,
59
+ version: "0.8.21",
60
+ }
61
+ manifest.initialization = {
62
+ packageTemplateIdentity: "canonical-package-template-digest-remains-separate-from-effective-bootstrap-overlay-file-digests",
63
+ repairStaging: "manifest-less-recognized-portable-static-baseline-records-the-caller-realpath-before-staging-ownership-verification",
64
+ }
65
+ manifest.projectFinishSourceIdentity = {
66
+ adoptedInstructionPolicy: "remains-source-bound",
67
+ repairInferenceObservations: "excludes-only-.persona/instructions/inferred.json-and-.persona/instructions/conflicts.json",
68
+ }
69
+ manifest.authority.readOnlyVerify.archiveInput = {
70
+ ...manifest.authority.readOnlyVerify.archiveInput,
71
+ ancestorDirectoryChurn: "same-no-follow-directory-location-and-mode-required-while-unrelated-entry-metadata-may-change",
72
+ directParentIntegrity: "full-no-follow-identity-remains-required-before-read",
73
+ }
74
+ manifest.authority.readOnlyVerify.artifactDigestInput = "canonical-sha256-prefix-or-exact-64-hex-normalized-before-archive-verification"
75
+ manifest.authority.fixturePlan.registryInstall = "requires-authorized-release-before-registry-install-persona-harness@0.8.22"
76
+ manifest.authority.hostedFixture.revision = "v0822-source-candidate-head-before-authorized-release"
77
+ manifest.hostedResidual.id = "v0822-current-package-acceptance-and-authorized-current-artifact-observation"
78
+ return manifest
79
+ }
80
+
81
+ function fail() {
82
+ throw new V0822AcceptanceManifestError("v0822-acceptance-schema")
83
+ }
@@ -0,0 +1,40 @@
1
+ export const V0823_ACCEPTANCE_SCHEMA_VERSION: "consumer-authority-v0823-acceptance.1"
2
+
3
+ export class V0823AcceptanceManifestError extends Error {
4
+ readonly code: "v0823-acceptance-schema"
5
+ }
6
+
7
+ export type V0823AcceptanceManifest = Readonly<Record<string, unknown>> & Readonly<{
8
+ readonly authority: Readonly<{
9
+ readonly readOnlyVerify: Readonly<{
10
+ readonly archiveInput: Readonly<{
11
+ readonly ancestorDirectoryChurn: string
12
+ readonly arbitrarySymlinkAncestorOrLeaf: string
13
+ readonly darwinSystemTemporaryAlias: string
14
+ readonly directParentIntegrity: string
15
+ readonly nonDarwin: string
16
+ }>
17
+ readonly artifactDigestInput: string
18
+ readonly command: string
19
+ readonly noCredentialFetchStoreConsumeFinishReplay: boolean
20
+ readonly schemaVersion: string
21
+ }>
22
+ }>
23
+ readonly package: Readonly<{
24
+ readonly channel: string
25
+ readonly scope: string
26
+ readonly version: string
27
+ }>
28
+ readonly initialization: Readonly<{
29
+ readonly packageTemplateIdentity: string
30
+ readonly repairStaging: string
31
+ }>
32
+ readonly projectFinishSourceIdentity: Readonly<{
33
+ readonly adoptedInstructionPolicy: string
34
+ readonly repairInferenceObservations: string
35
+ }>
36
+ }>
37
+
38
+ export function canonicalV0823AcceptanceManifest(): V0823AcceptanceManifest
39
+ export function readV0823AcceptanceManifest(packageRoot: string): V0823AcceptanceManifest
40
+ export function parseV0823AcceptanceManifest(value: unknown, packageVersion: string): V0823AcceptanceManifest
@@ -0,0 +1,83 @@
1
+ import { readFileSync } from "node:fs"
2
+ import { join } from "node:path"
3
+ import { isDeepStrictEqual } from "node:util"
4
+
5
+ import { canonicalV0822AcceptanceManifest } from "./consumer-authority-v0822-acceptance-schema.mjs"
6
+ import { parseCanonicalPackagePublisherPlan } from "./canonical-package-publisher.mjs"
7
+ import { parseExternalArtifactTransportPlan } from "./consumer-authority-external-artifact-transport-plan.mjs"
8
+ import { parseExternalAttestationCommandPlan } from "./consumer-authority-external-attestation-command-plan.mjs"
9
+ import { parseObserverGhToolContract } from "./consumer-authority-observer-gh-tool.mjs"
10
+
11
+ export const V0823_ACCEPTANCE_SCHEMA_VERSION = "consumer-authority-v0823-acceptance.1"
12
+
13
+ const V0823_PACKAGE_VERSION = "0.8.23"
14
+ const ACCEPTANCE_PATH = join("docs", "current", "release", "consumer-authority-v0823-acceptance.json")
15
+ const EXPECTED_MANIFEST = buildExpectedManifest()
16
+
17
+ export class V0823AcceptanceManifestError extends Error {
18
+ constructor(code) {
19
+ super(code)
20
+ this.code = code
21
+ }
22
+ }
23
+
24
+ export function canonicalV0823AcceptanceManifest() {
25
+ return structuredClone(EXPECTED_MANIFEST)
26
+ }
27
+
28
+ export function readV0823AcceptanceManifest(packageRoot) {
29
+ let packageVersion
30
+ let value
31
+ try {
32
+ packageVersion = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8")).version
33
+ value = JSON.parse(readFileSync(join(packageRoot, ACCEPTANCE_PATH), "utf8"))
34
+ } catch {
35
+ fail()
36
+ }
37
+ return parseV0823AcceptanceManifest(value, packageVersion)
38
+ }
39
+
40
+ export function parseV0823AcceptanceManifest(value, packageVersion) {
41
+ if (packageVersion !== V0823_PACKAGE_VERSION || !isDeepStrictEqual(value, EXPECTED_MANIFEST)) fail()
42
+ parseCanonicalPackagePublisherPlan(value.canonicalPackagePublisherPlan)
43
+ parseExternalAttestationCommandPlan(value.externalAttestationCommandPlan)
44
+ parseExternalArtifactTransportPlan(value.externalArtifactTransportPlan)
45
+ parseObserverGhToolContract(value.observerGhTool)
46
+ return value
47
+ }
48
+
49
+ function buildExpectedManifest() {
50
+ const manifest = canonicalV0822AcceptanceManifest()
51
+ manifest.schemaVersion = V0823_ACCEPTANCE_SCHEMA_VERSION
52
+ manifest.package.channel = "unpublished"
53
+ manifest.package.scope = "source-candidate"
54
+ manifest.package.version = V0823_PACKAGE_VERSION
55
+ delete manifest.v0821HistoricalRelease
56
+ manifest.v0822HistoricalRelease = {
57
+ outcome: "published-0.8.22-release-is-immutable-and-not-reusable-for-this-unpublished-v0823-source-candidate-or-any-later-package",
58
+ reusableForV0823: false,
59
+ version: "0.8.22",
60
+ }
61
+ manifest.initialization = {
62
+ packageTemplateIdentity: "canonical-package-template-digest-remains-separate-from-effective-bootstrap-overlay-file-digests",
63
+ repairStaging: "manifest-less-recognized-portable-static-baseline-records-the-caller-realpath-before-staging-ownership-verification",
64
+ }
65
+ manifest.projectFinishSourceIdentity = {
66
+ adoptedInstructionPolicy: "remains-source-bound",
67
+ repairInferenceObservations: "excludes-only-.persona/instructions/inferred.json-and-.persona/instructions/conflicts.json",
68
+ }
69
+ manifest.authority.readOnlyVerify.archiveInput = {
70
+ ...manifest.authority.readOnlyVerify.archiveInput,
71
+ ancestorDirectoryChurn: "same-no-follow-directory-location-and-mode-required-while-unrelated-entry-metadata-may-change",
72
+ directParentIntegrity: "full-no-follow-identity-remains-required-before-read",
73
+ }
74
+ manifest.authority.readOnlyVerify.artifactDigestInput = "canonical-sha256-prefix-or-exact-64-hex-normalized-before-archive-verification"
75
+ manifest.authority.fixturePlan.registryInstall = "requires-authorized-release-before-registry-install-persona-harness@0.8.23"
76
+ manifest.authority.hostedFixture.revision = "v0823-source-candidate-head-before-authorized-release"
77
+ manifest.hostedResidual.id = "v0823-current-package-acceptance-and-authorized-current-artifact-observation"
78
+ return manifest
79
+ }
80
+
81
+ function fail() {
82
+ throw new V0823AcceptanceManifestError("v0823-acceptance-schema")
83
+ }
@@ -2,7 +2,7 @@ import { realpathSync } from "node:fs"
2
2
  import { dirname } from "node:path"
3
3
  import { fileURLToPath, pathToFileURL } from "node:url"
4
4
 
5
- import { readV0821AcceptanceManifest } from "./consumer-authority-v0821-acceptance-schema.mjs"
5
+ import { readV0823AcceptanceManifest } from "./consumer-authority-v0823-acceptance-schema.mjs"
6
6
  import { runExternalArtifactTransportPreflight } from "./consumer-authority-external-artifact-transport-plan.mjs"
7
7
 
8
8
  const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)))
@@ -14,7 +14,7 @@ async function main() {
14
14
  process.exitCode = 1
15
15
  return
16
16
  }
17
- readV0821AcceptanceManifest(packageRoot)
17
+ readV0823AcceptanceManifest(packageRoot)
18
18
  const result = await runExternalArtifactTransportPreflight()
19
19
  process.stdout.write(`${JSON.stringify(result)}\n`)
20
20
  process.exitCode = result.state === "ready" ? 0 : 1
@@ -2,7 +2,7 @@ import { realpathSync } from "node:fs"
2
2
  import { dirname } from "node:path"
3
3
  import { fileURLToPath, pathToFileURL } from "node:url"
4
4
 
5
- import { readV0821AcceptanceManifest } from "./consumer-authority-v0821-acceptance-schema.mjs"
5
+ import { readV0823AcceptanceManifest } from "./consumer-authority-v0823-acceptance-schema.mjs"
6
6
  import { runExternalAttestationGrammarPreflight } from "./consumer-authority-external-attestation-command-plan.mjs"
7
7
 
8
8
  const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)))
@@ -15,7 +15,7 @@ function main() {
15
15
  process.exitCode = 1
16
16
  return
17
17
  }
18
- const manifest = readV0821AcceptanceManifest(packageRoot)
18
+ const manifest = readV0823AcceptanceManifest(packageRoot)
19
19
  const result = runExternalAttestationGrammarPreflight(
20
20
  manifest.externalAttestationCommandPlan,
21
21
  grammarOnlyTopology(manifest),
package/README.ja.md DELETED
@@ -1,163 +0,0 @@
1
- <!-- <CENTERED SECTION FOR GITHUB DISPLAY> -->
2
-
3
- <div align="center">
4
-
5
- <img src="img/Persona-Harness-Logo.png" alt="Persona Harness ロゴ" width="180">
6
-
7
- # Persona Harness
8
-
9
- **Java/Spring バックエンドを作る AI コーディングエージェントのための完了ゲート。**
10
-
11
- [![npm version](https://img.shields.io/npm/v/persona-harness?color=369eff&labelColor=black&style=flat-square)](https://www.npmjs.com/package/persona-harness)
12
- [![npm downloads](https://img.shields.io/npm/dt/persona-harness?color=ff6b35&labelColor=black&style=flat-square)](https://www.npmjs.com/package/persona-harness)
13
- [![node](https://img.shields.io/badge/node-%5E20.17.0%20%7C%7C%20%3E%3D22.9.0-c4f042?labelColor=black&style=flat-square)](https://nodejs.org)
14
- [![License](https://img.shields.io/badge/license-Apache--2.0-white?labelColor=black&style=flat-square)](./LICENSE)
15
-
16
- [English](README.md) | [한국어](README.ko.md) | [日本語](README.ja.md) | [简体中文](README.zh-cn.md)
17
-
18
- **[Start Here](docs/START-HERE.md) · [Quick Demo](docs/QUICK-DEMO.md) · [Measured Claims](docs/MEASURED-CLAIMS.md)**
19
-
20
- </div>
21
-
22
- <!-- </CENTERED SECTION FOR GITHUB DISPLAY> -->
23
-
24
- > AI エージェントは「完了しました!」と言いたがります — Persona Harness はそれを証明させます。必要な report、PH が生成した evidence、実際のテスト結果がディスク上に存在するまで完了主張をブロックするローカル CLI 完了ゲートです。
25
-
26
- > [!IMPORTANT]
27
- > **Alpha, gate-first, 測定ベース。** ライブの registry チャネル、タグ、GitHub リリース、audit lifecycle の事実は governed registry と audit record に保持されます。source documentation は自身の preparation boundary だけを記録します。runtime injection は **default-off / opt-in** です。[`docs/current/p3-integrity-roadmap.md`](docs/current/p3-integrity-roadmap.md)、[`docs/MEASURED-CLAIMS.md`](docs/MEASURED-CLAIMS.md)、[`injection-value-status.json`](docs/current/injection-value-status.json) を参照してください。
28
-
29
- ## 測定された動作 (Measured Behavior)
30
-
31
- 多くのエージェントハーネスプロジェクトと異なり、PH は実際に測定したものを — ネガティブな結果も含めて — 公開します。
32
-
33
- - **偽造された TDD evidence** を `workflow finish` の前に仕込む → `finish` が **exit 1**、偽造ファイルは無視。
34
- - **Green-only 完了**(TDD rail on)→ ブロック **5/5**(off では許可 5/5)。
35
- - **runtime injection**、10 ペアの OpenCode run → 成功率は同じ(両方 10/10)だが PH ON は全 10 ペアでコスト増 → **default-off** を維持。
36
-
37
- 限定されたローカル fixture での completion-integrity 測定です — トークン節約・アプリ品質・プロダクト効能の主張では*ありません*。完全な境界と根拠: **[docs/MEASURED-CLAIMS.md](docs/MEASURED-CLAIMS.md)**。
38
-
39
- ## これは何か
40
-
41
- AI エージェントが行う Java/Spring バックエンド作業のための workflow + evidence CLI(`ph`)と、任意の OpenCode プラグインです。行うこと:
42
-
43
- - プロジェクトのアイデアや README を実装 ticket に分割
44
- - エージェントを反復可能なバックエンド workflow に乗せ続ける
45
- - 制限されたコマンド実行で検証
46
- - 何を読み、実行し、完了したかをローカル evidence として記録
47
- - **必要な report/evidence がなければ完了をブロック**
48
-
49
- コード品質保証、トークン節約プロダクト、broad linter、生成アプリが production-ready である証明では**ありません**。完了ゲートより広いすべての主張は、先に測定によって獲得しなければなりません — [MEASURED-CLAIMS](docs/MEASURED-CLAIMS.md) を参照。
50
-
51
- ## インストール
52
-
53
- Node.js ^20.17.0 || >=22.9.0(Node 21 は未対応)、Java 21+ / Gradle、そしてプロバイダーが設定済みの OpenCode CLI が必要です。
54
-
55
- ```bash
56
- # OpenCode
57
- curl -fsSL https://opencode.ai/install | bash # または: npm install -g opencode-ai
58
- opencode auth login
59
-
60
- # Persona Harness
61
- npm install -D persona-harness
62
- npx ph --help && npx ph doctor
63
- ```
64
-
65
- ## クイックスタート
66
-
67
- クリーンなプロジェクトディレクトリでは、次の経路を使ってください(Persona Harness repo 自体は不可)。
68
-
69
- ```bash
70
- mkdir -p /tmp/ph-demo && cd /tmp/ph-demo && npm init -y
71
- npm install -D persona-harness
72
-
73
- npx ph init # 最小限の統合ファイルのみ
74
- npx ph bootstrap backend # AGENTS.md, profile, plan, report テンプレート
75
- npx ph workflow check
76
- ```
77
-
78
- 既存の Java/Spring/Gradle プロジェクトでは、まず推論された draft を確認してから
79
- 明示的に受け入れます。
80
-
81
- ```bash
82
- npx ph attach
83
- npx ph attach --yes
84
-
85
- # 認識済みの弱い Persona Harness インストールにのみ使用し、ready なものには使用しない:
86
- npx ph attach --repair --yes
87
- ```
88
-
89
- `attach` は、認識できない、または壊れた既存 Persona Harness ファイルを上書きせず
90
- 拒否し、すでに ready なインストールに対する repair も拒否します。attach が成功すると
91
- PH-run verification を有効にしますが、`runtimeInjection`、`systemConstitution`、
92
- `idleContinuation`、Ralph loop は off のままです。
93
-
94
- その後、OpenCode でエージェントにあなたの `README.md` を実装するよう依頼します。エージェントは自分で rail を回し、`npx ph workflow finish implement` で終えるはずです。
95
-
96
- > [!NOTE]
97
- > `workflow finish` が失敗した場合、エージェントは完了を主張する前に報告された blocker を修正しなければなりません。**その失敗はバグではなく、プロダクトが機能している証拠です。**
98
-
99
- サンプル Todo API とアイデア優先フローを含む完全なガイド: **[Quick Demo](docs/QUICK-DEMO.md)**。
100
-
101
- ## TDD Rail (opt-in)
102
-
103
- `.persona/harness.jsonc` で両方の設定を有効にします:
104
-
105
- ```json
106
- { "enforce": { "executeVerification": true, "tdd": true } }
107
- ```
108
-
109
- すると `ph workflow test` は **PH が直接実行した Gradle/JUnit の失敗からのみ** red evidence を記録します — エージェントが報告した evidence は決して受け付けません。その後 `workflow check` / `archive` / `finish` が同じ ticket/test id の green evidence を記録します。red-first 完了ゲートであり、テスト scaffolding・十分性の証明・coverage/mutation・アプリ品質の認証は行いません。
110
-
111
- ## コマンド
112
-
113
- ```bash
114
- npx ph attach [--yes] # 既存 Java/Spring/Gradle プロジェクト
115
- npx ph workflow check | implement | finish implement | archive <ticket-id>
116
- npx ph workflow split README.md && npx ph workflow next # マルチ ticket
117
- npx ph bearshell --shell 'gradle test' # 制限された実行
118
- npx ph evidence summary | metrics --json | ab-report --json | pminus-report --json
119
- npx ph review backend-shape
120
- ```
121
-
122
- 全リストは `npx ph --help`。workflow 台帳は `.persona/workflow/`(`work/`, `history/`, `requirements/`)にあります。
123
-
124
- ## オプション統合 (opt-in preview)
125
-
126
- ```bash
127
- npx ph bootstrap backend --codegraph-preview # CodeGraph
128
- npx ph bootstrap backend --lsp-preview # Java LSP
129
- npx ph bootstrap backend --runtime-injection-preview # parked model-facing guidance
130
- npx ph bootstrap backend --no-developer-mcp # 既定の developer MCP を無効化
131
- ```
132
-
133
- preview wrapper は外部ツールがない場合、成功を偽装せず **unavailable** 状態を報告します。runtime injection は parked(negative 測定)であり、推奨パスではありません。
134
-
135
- ## プラットフォームとホストのサポート
136
-
137
- | サーフェス | 状態 | 根拠の範囲 |
138
- | --- | --- | --- |
139
- | macOS / Linux + OpenCode | 検証済み | 現在の Persona Harness のホストアダプターとプロダクトの根拠は、macOS/Linux 上の OpenCode に限定されます。 |
140
- | Windows | 未検証 | Windows のサポートを主張しません。ロック identity の device/inode 動作と stale-lock/concurrency に関する結論は、測定も検証もされていません。 |
141
- | Codex adapter | 計画中 | 現在の Codex adapter または Codex プロダクトの根拠はありません。計画中の adapter にすぎません。 |
142
-
143
- ## 境界と安全
144
-
145
- Evidence は一つの質問にのみ答えます — *「エージェントは期待された rail を見て従ったか?」* — それ以上ではありません。PH はアプリ品質認証、トークン節約、Clean Code 保証、broad AST/linter 強制、full TDD フレームワーク、closure 保証、OpenCode なしの完全な workflow を**約束しません**。正規のリストは [MEASURED-CLAIMS](docs/MEASURED-CLAIMS.md) にあります。
146
-
147
- > [!WARNING]
148
- > `ph bearshell` は**サンドボックスではありません**。実行時間と出力サイズを制限しますが、コマンドはあなたのマシン上であなたの権限で実行されます。[SECURITY](SECURITY.md) を参照。
149
-
150
- ## ドキュメント
151
-
152
- - **新規ユーザー** → [Start Here](docs/START-HERE.md) · [Quick Demo](docs/QUICK-DEMO.md) · [Measured Claims](docs/MEASURED-CLAIMS.md)
153
- - **インストール & バックエンド形状** → [MVP インストールガイド](docs/current/java-backend-mvp-install-guide.md)
154
- - **コントリビューター** → [CONTRIBUTING](CONTRIBUTING.md) · [ROADMAP](ROADMAP.md) · [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md)
155
- - **リリース & 測定** → [リリース運用](docs/current/release/README.md) · [バージョン別リリース文書](docs/releases/README.md) · [パッケージインデックス](docs/releases/package-index.md) · [Changelog](CHANGELOG.md)
156
-
157
- ## コントリビュート
158
-
159
- コントリビュートを歓迎します — ネガティブな測定結果も含めて。PH は証拠が裏付けるものだけを主張し、主張を広げる PR はその測定を伴わなければなりません。[CONTRIBUTING.md](CONTRIBUTING.md) から読んでください。
160
-
161
- ## ライセンス
162
-
163
- Apache-2.0。[LICENSE](LICENSE) を参照してください。