From d42ce395462e37b332589175d5ff3dc8b156f423 Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 02:47:05 +0800 Subject: [PATCH 01/18] Freeze Passpod v0.1 specification and add SDK core --- docs/CONFORMANCE.md | 165 +++++++ docs/MESSAGE-MODEL.md | 117 +++++ docs/PASSPOD-RESET-AUDIT.md | 389 ++++++++++++++++ docs/PROFILES.md | 167 +++++++ docs/PROTOCOL.md | 112 +++++ docs/SPECIFICATION_FREEZE_REPORT.md | 344 ++++++++++++++ docs/STANDARD.md | 101 +++++ docs/STATE-MODEL.md | 128 ++++++ docs/TERMINOLOGY.md | 176 ++++++++ examples/invalid/close-before-agree.json | 47 ++ examples/invalid/duplicate-message-id.json | 30 ++ examples/invalid/invalid-transition.json | 30 ++ examples/invalid/missing-parent.json | 22 + examples/invalid/redefine-message-type.json | 23 + examples/valid/complete-handshake.json | 66 +++ examples/valid/minimal-profile.json | 10 + examples/valid/minimal-propose.json | 7 + examples/valid/propose-challenge-agree.json | 48 ++ examples/valid/propose-challenge.json | 32 ++ passpod/__init__.py | 12 + passpod/errors.py | 21 + passpod/handshake.py | 113 +++++ passpod/message.py | 90 ++++ passpod/profile.py | 70 +++ schemas/handshake.schema.json | 168 +++++++ schemas/message.schema.json | 182 ++++++++ schemas/profile.schema.json | 169 +++++++ tests/test_sdk_core.py | 254 +++++++++++ tests/test_semantic_validator.py | 221 +++++++++ validator/semantic_validator.py | 472 ++++++++++++++++++++ 30 files changed, 3786 insertions(+) create mode 100644 docs/CONFORMANCE.md create mode 100644 docs/MESSAGE-MODEL.md create mode 100644 docs/PASSPOD-RESET-AUDIT.md create mode 100644 docs/PROFILES.md create mode 100644 docs/PROTOCOL.md create mode 100644 docs/SPECIFICATION_FREEZE_REPORT.md create mode 100644 docs/STANDARD.md create mode 100644 docs/STATE-MODEL.md create mode 100644 docs/TERMINOLOGY.md create mode 100644 examples/invalid/close-before-agree.json create mode 100644 examples/invalid/duplicate-message-id.json create mode 100644 examples/invalid/invalid-transition.json create mode 100644 examples/invalid/missing-parent.json create mode 100644 examples/invalid/redefine-message-type.json create mode 100644 examples/valid/complete-handshake.json create mode 100644 examples/valid/minimal-profile.json create mode 100644 examples/valid/minimal-propose.json create mode 100644 examples/valid/propose-challenge-agree.json create mode 100644 examples/valid/propose-challenge.json create mode 100644 passpod/__init__.py create mode 100644 passpod/errors.py create mode 100644 passpod/handshake.py create mode 100644 passpod/message.py create mode 100644 passpod/profile.py create mode 100644 schemas/handshake.schema.json create mode 100644 schemas/message.schema.json create mode 100644 schemas/profile.schema.json create mode 100644 tests/test_sdk_core.py create mode 100644 tests/test_semantic_validator.py create mode 100644 validator/semantic_validator.py diff --git a/docs/CONFORMANCE.md b/docs/CONFORMANCE.md new file mode 100644 index 0000000..86184cb --- /dev/null +++ b/docs/CONFORMANCE.md @@ -0,0 +1,165 @@ +# Passpod Conformance + +## Status + +This document defines conceptual conformance for Passpod. + +It does not define tests, certification, implementation checklists, schemas, APIs, transports, SDK classes, validators, storage, signatures, cryptography, or implementation details. + +## Purpose + +Conformance describes what it means for documents, profiles, SDKs, validators, CLIs, and related materials to align with Passpod. + +Semantic conformance comes before implementation conformance. A system can only be implementation-conformant if it preserves the semantics of the Passpod Standard, the Handshake Protocol, and any declared profile. + +## Normative Language + +Normative language defines requirements for conformance. + +The terms `MUST`, `SHOULD`, `MAY`, and `MUST NOT` are used to express requirement levels within Passpod normative material. + +## MUST + +`MUST` indicates a required condition for conformance. + +If a conformant artifact claims to satisfy a normative requirement, it must preserve that requirement without redefining it through implementation detail, profile specialization, or extension behavior. + +## SHOULD + +`SHOULD` indicates a recommended condition for conformance. + +An artifact may vary from a `SHOULD` requirement only when the variance is intentional, justified by the applicable profile or context, and does not violate any `MUST` or `MUST NOT` requirement. + +## MAY + +`MAY` indicates an allowed option. + +An artifact may choose whether to implement, describe, or support a `MAY` behavior. Optional behavior must still preserve the Standard and the Handshake Protocol. + +## MUST NOT + +`MUST NOT` indicates a prohibited condition for conformance. + +An artifact that violates a `MUST NOT` requirement is not conformant for the affected scope. + +## Semantic Conformance + +Semantic conformance means preserving the meaning of the Passpod architecture. + +A semantically conformant artifact preserves: + +- the separation between Standard, protocol, message model, profiles, SDK, validators, CLI, documentation, and pilot work; +- the canonical protocol sequence `PROPOSE`, `CHALLENGE`, `AGREE`, `CLOSE`; +- transport neutrality; +- append-only handshake history; +- immutable accepted messages; +- profile specialization without core semantic redefinition; +- extension compatibility with the active architecture. + +## Standard Conformance + +Standard conformance means aligning with the Passpod Standard as the semantic authority. + +An artifact that claims Standard conformance MUST preserve the Standard's scope, objectives, non-objectives, conformance philosophy, and extension philosophy. + +An artifact MUST NOT treat transport, encoding, storage, signatures, cryptography, SDK structure, validator behavior, or CLI behavior as part of the Standard unless the Standard itself defines that meaning. + +## Protocol Conformance + +Protocol conformance means preserving the Handshake Protocol. + +A protocol-conformant artifact MUST preserve the canonical message meanings: + +- `PROPOSE` introduces or advances what a participant wants to establish; +- `CHALLENGE` asks for clarification, evidence, constraint, revision, qualification, or other negotiation work; +- `AGREE` records accepted negotiation meaning within handshake scope; +- `CLOSE` ends active negotiation and records terminal outcome. + +Profiles MAY extend the protocol, but profiles MUST NOT redefine `PROPOSE`, `CHALLENGE`, `AGREE`, or `CLOSE`. + +## Message Model Conformance + +Message Model conformance means preserving the conceptual relationships among messages, handshakes, participants, profiles, evidence, references, versions, and extensions. + +A conformant message model artifact MUST keep representation unspecified unless it is explicitly defining a separate serialization or implementation layer. + +A conformant message model artifact MUST NOT make JSON, a transport, a storage system, a signature mechanism, or an SDK class required by the core message model. + +## Profile Conformance + +Profile conformance means specializing Passpod without redefining Passpod. + +A conformant profile MAY define domain-specific participant roles, evidence expectations, extension rules, version expectations, and terminal meanings. + +A conformant profile MUST preserve the Standard, the Handshake Protocol, and the Message Model. + +A conformant profile MUST NOT reintroduce archived legacy terminology as active architecture. + +## SDK Conformance + +SDK conformance means implementing the protocol while preserving Passpod semantics. + +A conformant SDK SHOULD help developers create, interpret, transmit, store, inspect, or validate protocol messages in ways that preserve the Standard and any declared profile. + +A conformant SDK MUST NOT redefine protocol message meanings through class names, runtime behavior, helper methods, or implementation convenience. + +## Validator Conformance + +Validator conformance means evaluating declared conformance without becoming the source of protocol meaning. + +A conformant validator MAY check artifacts against the Standard, protocol, message model, profiles, or future machine-readable definitions. + +A conformant validator MUST NOT make its own implementation assumptions normative unless those assumptions are defined by the applicable normative material. + +## CLI Conformance + +CLI conformance means exposing developer-facing operations without changing protocol semantics. + +A conformant CLI MAY help compose, inspect, validate, or explain Passpod artifacts. + +A conformant CLI MUST preserve the Standard, protocol, message model, and declared profile semantics. + +## Documentation Conformance + +Documentation conformance means describing Passpod without contradicting the normative architecture. + +Conformant documentation SHOULD clearly distinguish normative requirements from informative explanation. + +Conformant documentation MUST NOT present archived legacy terminology as active architecture. + +## Future Conformance Classes + +Future conformance classes may group requirements by artifact type. These classes are conceptual and do not define tests, certification, or implementation checklists. + +### Core Conformance + +Core conformance means preserving the Passpod Standard, Handshake Protocol, Message Model, and active terminology. + +### Profile Conformance + +Profile conformance means preserving core conformance while adding domain-specific specialization. + +### SDK Conformance + +SDK conformance means preserving core and declared profile conformance in developer-facing implementation. + +### Validator Conformance + +Validator conformance means evaluating declared requirements while preserving the authority of the normative material being evaluated. + +## Non-goals + +This document does not define: + +- tests; +- certification; +- implementation checklists; +- schemas; +- APIs; +- SDK classes; +- validators; +- CLI commands; +- storage rules; +- signature rules; +- cryptographic requirements. + diff --git a/docs/MESSAGE-MODEL.md b/docs/MESSAGE-MODEL.md new file mode 100644 index 0000000..d11f9ff --- /dev/null +++ b/docs/MESSAGE-MODEL.md @@ -0,0 +1,117 @@ +# Passpod Message Model + +## Status + +This document defines the conceptual structure of a Passpod message. + +Representation is intentionally unspecified. JSON is only one possible serialization. Message fields named here are informative examples, not protocol requirements. + +This document does not define JSON, schemas, APIs, transports, SDK classes, storage, signatures, cryptography, or implementation details. + +## Purpose + +The message model explains how messages relate to handshakes, participants, profiles, evidence, references, versions, and extensions. + +The model provides shared vocabulary for future schemas, SDKs, validators, profiles, and documentation without committing Passpod to a particular encoding. + +## Conceptual Message + +A Passpod message is a unit of communication within a handshake. + +Once accepted into handshake history, a message is treated as immutable. Later messages may refer to it, qualify it, supersede its negotiation meaning, or close the handshake, but they do not rewrite the accepted message. + +## Message Identity + +Message identity is the conceptual ability to distinguish one message from another. + +An implementation may need message identity to support references, reviewability, lineage, and append-only history. The protocol does not prescribe how identity is represented. + +## Handshake Identity + +Handshake identity is the conceptual ability to associate messages with the same handshake. + +A message belongs to a handshake context. The handshake identity gives participants a way to understand that a message is part of a bounded negotiation history. + +## Parent Reference + +A parent reference relates a message to earlier handshake context. + +Parent references preserve negotiation lineage. They can show what a message responds to, depends on, revises, challenges, accepts, or closes. + +The representation of parent references is intentionally unspecified. + +## Sender + +The sender is the participant responsible for emitting a message. + +The sender concept does not require a specific identity system, authorization model, credential format, or runtime. Profiles may specialize sender expectations. + +## Recipient + +The recipient is the participant, participants, role, or audience addressed by a message. + +A recipient may be explicit, profile-defined, inferred from the handshake context, or otherwise determined by a conformant implementation or profile. The core message model does not prescribe addressing mechanics. + +## Timestamp Concept + +A timestamp concept supports ordering, reviewability, and interpretation of handshake history. + +The message model does not prescribe time format, clock source, precision, authority, synchronization, or storage behavior. Profiles may define stricter expectations when timing is material to a domain. + +## Message Type + +Message type is the conceptual role a message plays in the handshake. + +The canonical protocol message types are `PROPOSE`, `CHALLENGE`, `AGREE`, and `CLOSE`. Profiles may add domain-specific distinctions, but they must not redefine the core meaning of the canonical message types. + +## Profile Association + +Profile association identifies the profile context that specializes a message or handshake. + +A profile association helps participants interpret domain-specific expectations, evidence conventions, extension rules, and conformance obligations. The message model does not prescribe how profile association is encoded. + +## Version Association + +Version association identifies the relevant version context for the Standard, protocol, message model, profile, or extension. + +Version association supports compatibility and interpretation. It does not require a particular versioning scheme. + +## Evidence References + +Evidence references connect a message to evidence used to support, question, qualify, or resolve negotiation. + +Evidence may be introduced by proposals, requested by challenges, accepted in agreements, or summarized at closure. The message model does not define evidence format, storage, verification, or trust mechanics. + +## Extension Points + +Extension points allow compatible specialization without changing the core architecture. + +Extensions may add domain meaning, profile conventions, transport bindings, or implementation capabilities. Extensions must preserve the Standard, the Handshake Protocol, and the append-only message history. + +## Conceptual Relationships + +A message belongs to a handshake. + +A handshake is a bounded negotiation history between participants. + +A participant emits, receives, interprets, or responds to messages. + +A profile specializes how messages and handshakes are interpreted for a domain or workflow. + +Evidence supports, questions, qualifies, or resolves negotiation meaning. + +An extension adds compatible specialization without redefining core semantics. + +## Non-requirements + +This message model does not require: + +- a specific data format; +- a specific serialization; +- a specific transport; +- a specific identity system; +- a specific storage system; +- a specific signature or cryptographic mechanism; +- a specific SDK structure; +- a specific validator design. + diff --git a/docs/PASSPOD-RESET-AUDIT.md b/docs/PASSPOD-RESET-AUDIT.md new file mode 100644 index 0000000..bb471f7 --- /dev/null +++ b/docs/PASSPOD-RESET-AUDIT.md @@ -0,0 +1,389 @@ +# Passpod Reset Audit + +Audit date: 2026-07-19 +Repository audited: `/Users/liping/passpod-task` +Branch observed: `main` +Remote observed: `https://github.com/edidx/passpod-task.git` +Audit mode: read-only audit plus this single new report file + +## 1. Executive summary + +The current repository is implemented as a public "Passpod TASK Core" standard/test repository. It is not yet aligned with the reset architecture: + +- Passpod Standard +- Passpod Handshake Protocol +- Passpod SDK +- Reference Profiles +- Passpod Pilot + +No tracked product asset in the repository currently expresses the canonical handshake `PROPOSE -> CHALLENGE -> AGREE -> CLOSE`. + +The active public surface still presents the legacy stack as `Passpod TASK Core -> Passpod Hub -> Control Packs -> Pilot Access -> paid pilot / Team / Enterprise`. That stack appears in `README.md`, `COMMERCIAL_BOUNDARY.md`, `SPEC.md`, `docs/glossary.md`, and the public gate script. The validation gate currently enforces old product terms, including `Passpod TASK Core`, `Passpod Hub`, `Control Packs`, `AgentTrust`, `Remote Worker Trust`, `Pilot Access Engine`, `Sensitive Action Control`, and `DIDX`. + +The repository has useful reusable material: JSON Schema validation patterns, demo-fixture safety checks, documentation boundary patterns, threat-model prompts, CI structure, and public/private data leakage checks. However, the current schema, OpenAPI route shape, examples, documentation, navigation, badge, GitHub Action name, and repo identity are contaminated by archived TASK/Hub/Control Pack/Pilot Access Engine language. + +No real secrets, tokens, credentials, production keys, real user data, or private pilot submissions were found in the tracked files. The only email-like operational contact found is `pilots@passpod.io`. The JSON examples use demo actors and demo subjects. The repo contains no package metadata, package exports, deployment configuration, Cloudflare config, application routes, HTML pages, or public website navigation beyond Markdown links and the OpenAPI reference. + +High breakage risk: removing or archiving legacy assets before updating the gate will break CI. The current CI calls `tools/check-public-task-repo.sh`, and that script requires the old file set and old terminology. + +Recommended bounded next pass: create a migration plan for the public surface and validation gate only, covering `README.md`, `SPEC.md`, `docs/glossary.md`, `PILOT_ACCESS.md`, `openapi/passpod-task.public.yaml`, `schemas/trust-action-receipt.schema.json`, `examples/`, `.github/workflows/validate.yml`, and `tools/check-public-task-repo.sh`, without changing implementation code. + +## 2. Repository architecture as currently implemented + +Current implementation shape: + +- Public documentation layer: top-level Markdown files plus `docs/*.md`. +- Public schema layer: `schemas/trust-action-receipt.schema.json`. +- Public example fixture layer: `examples/*.receipt.json`. +- Public OpenAPI reference layer: `openapi/passpod-task.public.yaml`. +- Public validator tooling: `tools/validate-receipts.py`. +- Public repository gate: `tools/check-public-task-repo.sh`. +- Pilot scoring helper: `tools/pilot-readiness.py`. +- Placeholder documentation directories: `cli/`, `validator/`, `worker-reference/`. +- CI: `.github/workflows/validate.yml`. +- Governance metadata: `.github/CODEOWNERS`, `.github/PULL_REQUEST_TEMPLATE.md`, `LICENSE`, `CODE_OF_CONDUCT.md`, `CONTRIBUTING.md`, `SECURITY.md`, `GOVERNANCE.md`. + +No source implementation exists in tracked files under `src/`, `spec/`, or `packages/validator`; those directories are present but empty and untracked by git. No package manager metadata, SDK package, API server, Cloudflare Worker, website, HTML, navigation code, or deployment configuration exists in this repository. + +Active inbound dependency shorthand used below: + +- `README nav`: public Markdown links from `README.md`. +- `CI`: `.github/workflows/validate.yml`. +- `gate`: `tools/check-public-task-repo.sh`. +- `validator`: `tools/validate-receipts.py`. +- `example docs`: `examples/README.md`. +- `OpenAPI`: `openapi/passpod-task.public.yaml`. + +## 3. Canonical assets + +No existing tracked product file is canonical under the reset architecture. The repository contains no active Standard document, no Handshake Protocol document, no SDK package, no Reference Profile hierarchy, and no Passpod Pilot material that avoids the legacy Pilot Access Engine/Hub stack. + +| Exact path | Classification | Current purpose | Why it supports or conflicts | Active inbound references | Active outbound references | Dependencies | Recommended action | Deletion risk | Human review | +|---|---|---|---|---|---|---|---|---|---| +| `docs/PASSPOD-RESET-AUDIT.md` | CANONICAL | This audit report only. | Supports reset governance by documenting migration scope; not an active product asset. | New file requested by audit. | References audited repository paths only. | None. | Keep as reset record. | Low. | No, unless facts are disputed. | + +## 4. Reusable assets + +| Exact path | Classification | Current purpose | Why it supports or conflicts | Active inbound references | Active outbound references | Dependencies | Recommended action | Deletion risk | Human review | +|---|---|---|---|---|---|---|---|---|---| +| `.github/CODEOWNERS` | REUSABLE | Assigns ownership to `@edidx`. | Generic repository governance; no product conflict, but ownership may need business confirmation. | GitHub CODEOWNERS behavior. | None. | GitHub review routing. | Keep unless owner changes. | Medium if removed, because review routing changes. | Yes for ownership. | +| `CODE_OF_CONDUCT.md` | REUSABLE | Minimal conduct statement. | Generic and not tied to legacy architecture. | None found. | None. | Public community expectations. | Keep or expand later. | Low. | No. | +| `CONTRIBUTING.md` | REUSABLE | Contribution guidance and private-data exclusion. | Useful public boundary pattern; contains scoped-key phrasing that should be checked during migration. | `gate` required file. | None. | CI gate currently requires it. | Retain pattern, adjust terms only during migration. | Medium before gate update. | Yes for public contribution policy. | +| `LICENSE` | REUSABLE | MIT license with DIDX copyright. | Legal asset, not product architecture. DIDX label needs legal/stewardship confirmation. | `OpenAPI` license name says "See repository LICENSE". | None. | Legal reuse rights; OpenAPI metadata references it. | Do not change in cleanup pass. | High if removed or altered. | Yes, legal approval required. | +| `requirements.txt` | REUSABLE | Pins `jsonschema[format]>=4,<5`. | Supports reusable validation tooling. | `CI`, `cli/README.md`, `validator/README.md`, `examples/README.md`, `validator`. | Python dependency spec. | Required for local and CI validation. | Keep until validation stack changes. | High before validator migration. | No. | +| `tools/validate-receipts.py` | REUSABLE | Validates example receipts against schema and public safety markers. | Strong reusable validation pattern; currently tied to Trust Action Receipt schema, demo signature, and old example directory. | `CI` via `gate`, `cli/README.md`, `validator/README.md`, `examples/README.md`, `gate`. | `schemas/trust-action-receipt.schema.json`, `examples/*.receipt.json`, `jsonschema`. | Required by current gate. | Retarget to canonical handshake/profile fixtures after schema migration. | High before replacement because CI depends on it. | No for mechanics; yes for new validation policy. | +| `docs/threat-model.md` | REUSABLE | Lists generic risks: forged receipts, bypassed controls, excessive evidence, confused authority, private leakage. | Useful threat prompts for Standard/Handshake/Profile work; not heavily branded. | None found. | None. | None. | Adapt into canonical Standard/SDK security notes. | Low. | Yes for security semantics. | + +## 5. Assets requiring migration + +| Exact path | Classification | Current purpose | Why it supports or conflicts | Active inbound references | Active outbound references | Dependencies | Recommended action | Deletion risk | Human review | +|---|---|---|---|---|---|---|---|---|---| +| `README.md` | MIGRATE | Main public entry, badge, stack position, start-here links, public/private boundary. | Publicly presents TASK Core, Hub, Control Packs, AgentTrust, Remote Worker Trust, Pilot Access Engine, DIDX, and sensitive-action doctrine as active. No canonical handshake or SDK path. | GitHub landing page; `gate` checks many phrases. | `SPEC.md`, schema, OpenAPI, examples, validator, `PILOT_ACCESS.md`, `COMMERCIAL_BOUNDARY.md`, `ROADMAP.md`, `FUNDING_USE.md`, GitHub Actions badge. | Removing or changing terms breaks `gate`. | Rewrite to Standard -> SDK -> reference profile -> validation -> workflow-fit assessment -> paid pilot path after gate update. | High. | Yes, public positioning. | +| `SPEC.md` | MIGRATE | Public v0.1 TASK Core specification. | Defines TASK decision model, Trust Action Receipt, `allow/deny/review_required/freeze/revoke`, AgentTrust, Remote Worker Trust, Hub, Control Packs, Pilot Access Engine. Conflicts with canonical handshake. | `README nav`, `gate`. | Schema, examples, Pilot Access, Hub/Control Pack stack. | Gate enforces phrases from it. | Replace with Passpod Standard and Handshake Protocol semantics. Preserve useful boundary disclaimers. | High. | Yes, standard semantics. | +| `ROADMAP.md` | MIGRATE | Public TASK Core roadmap. | Roadmap centers Trust Action Receipt, freeze/revocation, validator, OpenAPI, OSS maintenance; not reset sequence. | `README nav`. | None. | Public roadmap expectations. | Reframe to Standard, SDK, Reference Profiles, external validation, workflow-fit assessment, paid pilot. | Medium. | Yes, strategy. | +| `ADOPTION.md` | MIGRATE | Adoption reader paths. | Uses TASK Core, Sensitive Action Control, Hub, Pilot Access Engine, Passpod Protocol, Sentinel/Ops exclusions. | `gate`. | None. | Gate requires wording from it. | Rewrite reader paths for Standard, SDK adopters, validators, and pilot buyers. | High before gate update. | Yes, public funnel. | +| `COMMERCIAL_BOUNDARY.md` | MIGRATE | Public/commercial boundary. | Explicit old product stack: TASK Core -> Hub -> Control Packs -> Pilot Access -> paid pilot / Team / Enterprise. | `README nav`, `gate`. | None. | Gate requires Hub and stack wording. | Reframe around workflow-fit assessment, paid pilot, implementation/support, managed services only after demand. | High before gate update. | Yes, commercial positioning. | +| `FUNDING_USE.md` | MIGRATE | OSS funding/credits plan. | Describes TASK Core and decision states as active; contains standards crosswalk material that may be reusable. | `README nav`. | None. | Public funding narrative. | Update only with explicit funding/strategy approval. | Medium. | Yes, fundraising/public claims. | +| `GOVERNANCE.md` | MIGRATE | Stewardship note. | Says TASK Core is stewarded by DIDX and pilots handled through scoped Pilot Access. DIDX may remain legal, but active TASK/Pilot Access phrasing conflicts. | `gate`. | None. | Governance expectations. | Human-confirm legal/steward model, then update product terms. | Medium. | Yes, legal/stewardship. | +| `LAUNCH_READINESS.md` | MIGRATE | v0.1 launch checklist. | Encodes old launch success criteria: Pilot Access path, TASK Core, Sensitive Action Control, Hub exclusions, paid pilot/Team/Enterprise. | `gate`. | None. | Public/internal launch readiness. | Convert to reset readiness checklist only after public surface plan is approved. | Medium. | Yes, launch strategy. | +| `PILOT_ACCESS.md` | MIGRATE | Current pilot access page. | Has legitimate future paid-pilot material, but routes through Passpod Hub and Pilot Access Engine. | `README nav`, `gate`. | None. | Public pilot funnel; `pilots@passpod.io` checks. | Rewrite as Passpod Pilot and paid workflow-fit assessment. Do not treat all pilot content as obsolete. | High. | Yes, commercial/ops. | +| `SECURITY.md` | MIGRATE | Security contact. | Useful, but contact is `pilots@passpod.io`; may conflate security reporting with pilot funnel. | `gate` checks contact. | None. | Public security process. | Confirm whether security contact should remain pilot mailbox or become dedicated security channel. | Medium. | Yes, security ops. | +| `VERSIONING.md` | MIGRATE | Public draft version ladder. | Versioning belongs to old receipt core, not reset Standard/SDK/Profile release tracks. | `gate`. | None. | Gate requires file. | Replace with reset versioning policy after artifacts are named. | Medium. | Yes, release policy. | +| `.github/PULL_REQUEST_TEMPLATE.md` | MIGRATE | Public TASK repo checklist. | Checklist title and gate command are TASK-specific; private-data checks are reusable. | GitHub PR UI. | `tools/check-public-task-repo.sh`. | Developer workflow. | Update after gate is renamed/retargeted. | Medium. | No for mechanics; yes for policy wording. | +| `.github/workflows/validate.yml` | MIGRATE | CI validation workflow. | Workflow name is "Validate TASK public repo" and validates old examples plus old gate. | README badge references workflow path. | `requirements.txt`, schema JSON, three example JSON files, `tools/check-public-task-repo.sh`. | CI and README badge. | Retarget after schema/examples/gate migration. | High if changed first. | No for mechanics; yes for required checks. | +| `cli/README.md` | MIGRATE | States no standalone CLI, points to validator. | Useful CLI boundary, but blocks production signing via Hub/Pilot Access Engine language and does not describe SDK developer path. | `gate`, README mentions Validator not CLI directly. | `requirements.txt`, `tools/validate-receipts.py`. | Gate requires it. | Convert to SDK/CLI boundary or archive if no CLI remains. | Medium. | Yes if CLI becomes SDK surface. | +| `docs/glossary.md` | MIGRATE | Defines public vocabulary. | Central contamination file: TASK Core, Passpod Protocol as control doctrine, Hub, Control Packs, AgentTrust, Remote Worker Trust, Pilot Access Engine, DIDX. | `gate`. | None. | Gate requires terms from it. | Replace with reset glossary: Standard, Handshake Protocol, SDK, Reference Profiles, Passpod Pilot. | High before gate update. | Yes, naming authority. | +| `docs/non-goals.md` | MIGRATE | Short list of what TASK is not. | Boundary ideas are reusable, but active subject is TASK. | None found. | None. | None. | Rewrite around Passpod Standard/Protocol non-goals. | Low. | Yes for doctrine. | +| `docs/production-checklist.md` | MIGRATE | Production checklist. | Contains TASK plus freeze/revoke behavior. Useful controls checklist, but old decision model is central. | `gate`. | None. | Gate requires it. | Rewrite around handshake, profile validation, pilot readiness, implementation/support. | Medium. | Yes for security/process. | +| `docs/public-vs-pilot.md` | MIGRATE | Public vs pilot distinction. | Legitimate pilot distinction, but current shape is scoped keys, hosted endpoint, signed pilot receipts, Pilot Access. | `gate`. | None. | Gate requires it. | Convert to public Standard/SDK/reference profile vs paid workflow-fit/pilot boundary. | Medium. | Yes, public/commercial boundary. | +| `docs/receipt-lifecycle.md` | MIGRATE | Receipt lifecycle. | Uses `Request -> TASK check -> decision -> Trust Action Receipt`. Conflicts with canonical handshake sequence. | None found. | None. | None. | Replace with `PROPOSE -> CHALLENGE -> AGREE -> CLOSE` lifecycle. | Low. | Yes, protocol semantics. | +| `docs/security-model.md` | MIGRATE | Security model note. | Says TASK is control-and-receipt layer and production signing through Pilot Access. | None found. | None. | None. | Rewrite around Standard/Handshake/SDK trust boundaries. | Low. | Yes, security semantics. | +| `docs/standardization-roadmap.md` | MIGRATE | Public standardization progression. | Contains useful public feedback/external compatibility shape, but old v0.1/v0.2/v1 receipt-core path is not reset strategy. | `gate`. | None. | Gate requires it. | Reframe around Standard, SDK, reference profile, external validation. | Medium. | Yes, strategy. | +| `examples/README.md` | MIGRATE | Explains public demo receipts. | Documents TASK Core, Hub, Pilot Access Engine, Remote Worker TrustPass, freeze, and agent behavior examples. | `README nav`, `gate`. | Three example JSON files, `requirements.txt`, `tools/validate-receipts.py`. | Gate and docs. | Rewrite when examples become canonical reference-profile fixtures. | High before examples/gate update. | Yes for public examples. | +| `examples/refund-review.receipt.json` | MIGRATE | Demo high-risk refund review fixture. | Potentially reusable as a reference profile example, but currently uses `AgentTrust Live Control API` and old receipt/decision model. | `CI`, `validator`, `example docs`. | Schema fields. | Required by CI JSON check and validator. | Retain until replacement fixture exists; migrate concept away from Live Control API. | High before CI update. | Yes for scenario meaning. | +| `examples/remote-worker.receipt.json` | MIGRATE | Demo remote worker reference fixture. | Could become a reference profile, but currently uses Remote Worker TrustPass naming and old receipt/decision model. | `CI`, `gate`, `validator`, `example docs`, `tools/pilot-readiness.py` usage text. | Schema fields. | Required by CI JSON check, gate, validator, pilot helper usage. | Migrate into a canonical Reference Profile if remote-work remains approved. | High before CI/gate/helper update. | Yes for profile approval. | +| `openapi/README.md` | MIGRATE | Explains public OpenAPI reference. | Useful API boundary language, but tied to TASK Core, Hub, Pilot Access Engine, receipt lookup. | `gate`. | `openapi/passpod-task.public.yaml`. | Gate requires it. | Rewrite for SDK/reference validation API only if an API remains in reset scope. | Medium. | Yes, API surface. | +| `openapi/passpod-task.public.yaml` | MIGRATE | Public reference API shape. | Defines `/v1/spec`, `/v1/receipts/validate`, `/v1/receipts/{receipt_id}` and TASK receipt schemas. No canonical handshake routes. | `README nav`, `gate`, `openapi/README.md`. | Schema URL, LICENSE, `pilots@passpod.io`. | CI only JSON-checks examples/schema, not this YAML; gate requires file exists. | Replace or archive after deciding whether reset has public API routes or SDK-only validation. | Medium to high for clients using the reference. | Yes, public API contract. | +| `schemas/trust-action-receipt.schema.json` | MIGRATE | JSON Schema for Trust Action Receipt. | Reusable schema discipline, but title and fields encode TASK receipt and central `allow/deny/review_required/freeze/revoke` model. | `README nav`, `SPEC.md`, `validator`, `CI`, `gate`, `OpenAPI`. | JSON Schema draft URL. | Required by validator and CI. | Design canonical handshake/profile schema before changing. | High. | Yes, protocol/schema. | +| `tools/check-public-task-repo.sh` | MIGRATE | Public repo gate. | Major blocker: enforces old architecture, old README links, Pilot Access Engine, Hub, Control Packs, AgentTrust, Remote Worker Trust, Sensitive Action Control, DIDX, and old required files. | `CI`, `.github/PULL_REQUEST_TEMPLATE.md`. | Many docs, schema, examples, `tools/validate-receipts.py`, dangerous-pattern grep. | CI fails if changed incompatibly. | First gate to redesign in any cleanup pass; preserve secret/private-data checks. | High. | Yes for policy assertions. | +| `tools/pilot-readiness.py` | MIGRATE | Scores a receipt for production readiness. | Could inform paid workflow-fit assessment, but currently depends on receipt fields, `policy_ref`, `proof_ref`, demo signatures, and Pilot Access email. | None except self usage text. | Arbitrary input receipt path; no writes. | No CI dependency found. | Migrate to workflow-fit assessment only if scoring remains approved. | Low to medium. | Yes, commercial/security scoring. | +| `validator/README.md` | MIGRATE | Validator documentation. | Useful local validation instructions, but tied to Trust Action Receipts, demo signatures, Hub, Pilot Access Engine. | `README nav`, `gate`. | Schema, examples, `requirements.txt`, `tools/validate-receipts.py`. | Gate requires it. | Rewrite with canonical validation target after schema/examples migration. | Medium. | No for mechanics; yes for semantics. | + +## 6. Archive candidates + +| Exact path | Classification | Current purpose | Why it supports or conflicts | Active inbound references | Active outbound references | Dependencies | Recommended action | Deletion risk | Human review | +|---|---|---|---|---|---|---|---|---|---| +| `CHANGELOG.md` | ARCHIVE | Historical v0.1.0 note. | Useful as historical evidence of the TASK public draft; not a reset roadmap. | None found. | None. | Public release history. | Preserve as historical record or replace only with explicit release-history plan. | Medium if deleted because history is lost. | Yes for release history. | +| `examples/agent-freeze.receipt.json` | ARCHIVE | Demo agent emergency freeze fixture. | Tightly coupled to AgentTrust, Kill-State API, freeze action, and old execution-control model. Historically useful, but should not remain active public fixture in reset architecture. | `CI`, `validator`, `example docs`. | Schema fields. | Required by CI JSON check and validator. | Archive only after CI/gate/examples are migrated to canonical fixtures. | High before CI update. | Yes, because it is active in tests. | + +## 7. Delete candidates + +These are not tracked by git, but they exist in the working tree as empty directories. + +| Exact path | Classification | Current purpose | Why it supports or conflicts | Active inbound references | Active outbound references | Dependencies | Recommended action | Deletion risk | Human review | +|---|---|---|---|---|---|---|---|---|---| +| `packages/validator/` | DELETE-CANDIDATE | Empty local placeholder directory. | Could be intended SDK/validator package space, but contains no tracked files. | None found. | None. | None observed. | Do not delete during reset audit. Confirm whether it is an intentional SDK placeholder before removal. | Low in git, unknown locally. | Yes. | +| `spec/` | DELETE-CANDIDATE | Empty local placeholder directory. | Could be intended canonical spec space, but contains no tracked files. | None found. | None. | None observed. | Confirm before removal; may be useful for future Standard source. | Low in git, unknown locally. | Yes. | +| `src/` | DELETE-CANDIDATE | Empty local placeholder directory. | Could be intended implementation space, but contains no tracked files. | None found. | None. | None observed. | Confirm before removal; do not infer broader unused state from emptiness alone. | Low in git, unknown locally. | Yes. | + +## 8. Deferred assets + +| Exact path | Classification | Current purpose | Why it supports or conflicts | Active inbound references | Active outbound references | Dependencies | Recommended action | Deletion risk | Human review | +|---|---|---|---|---|---|---|---|---|---| +| `worker-reference/` | DEFER | Directory for future minimal public reference Worker docs. | Not part of immediate reset architecture unless converted into SDK/reference implementation material. | `gate` through README file. | `worker-reference/README.md`. | Gate requires README. | Leave untouched until Standard/SDK/reference implementation scope is decided. | Medium before gate update. | Yes. | +| `worker-reference/README.md` | DEFER | States no production Worker/issuer/Hub component exists. | Contains legacy Hub and Pilot Access Engine language; future Worker may be irrelevant to reset path. | `gate`. | None. | Gate requires it. | Defer; if kept, migrate later to SDK/reference implementation boundary. | Medium. | Yes. | + +## 9. TASK Guard contamination map + +Literal `TASK Guard` was not found in tracked files. However, TASK and related execution-control concepts are active throughout the repository. + +Pure legacy branding: + +- `README.md`: `Passpod TASK Core`, `Validate TASK public repo`, and old public stack. +- `SPEC.md`: `Passpod TASK Core Specification`, `TASK check`, `TASK decision`. +- `ROADMAP.md`, `ADOPTION.md`, `COMMERCIAL_BOUNDARY.md`, `FUNDING_USE.md`, `docs/glossary.md`, `docs/non-goals.md`, `docs/production-checklist.md`, `docs/security-model.md`, `docs/receipt-lifecycle.md`, `openapi/README.md`, `openapi/passpod-task.public.yaml`. +- `.github/workflows/validate.yml`: workflow name `Validate TASK public repo`. +- `.github/PULL_REQUEST_TEMPLATE.md`: `Public TASK repo checklist`. + +Reusable validation or receipt infrastructure: + +- `tools/validate-receipts.py`: reusable schema-validation and public-safety marker scanning. +- `requirements.txt`: reusable dependency. +- `schemas/trust-action-receipt.schema.json`: reusable schema practice, but schema semantics must be migrated. +- `examples/*.receipt.json`: fixture pattern reusable, current content not canonical. + +Tightly coupled execution-control code or data: + +- `schemas/trust-action-receipt.schema.json`: central `decision` enum includes `allow`, `deny`, `review_required`, `freeze`, `revoke`. +- `SPEC.md`: defines decision meanings around continuing, rejecting, pausing, and revoking actions. +- `examples/agent-freeze.receipt.json`: `AgentTrust Kill-State API`, `freeze_agent_execution`, `decision: freeze`. +- `examples/refund-review.receipt.json`: `AgentTrust Live Control API`. +- `docs/production-checklist.md`: `freeze/revoke behavior`. + +Public-facing contamination: + +- `README.md` and GitHub badge expose `passpod-task`. +- `SPEC.md`, `COMMERCIAL_BOUNDARY.md`, `PILOT_ACCESS.md`, `ADOPTION.md`, `docs/glossary.md`, `examples/README.md`, `openapi/README.md`, `openapi/passpod-task.public.yaml`, `validator/README.md`, `cli/README.md`, `worker-reference/README.md`. +- `tools/check-public-task-repo.sh` enforces contaminated terms as required. + +Historical material worth preserving: + +- `CHANGELOG.md`: v0.1.0 public draft record. +- `examples/agent-freeze.receipt.json`: useful record of the archived Kill-State/execution-control experiment after it is removed from active CI. + +## 10. Pilot architecture contamination map + +Legitimate future paid-pilot material: + +- `PILOT_ACCESS.md`: contains a real funnel concept that maps to Passpod Pilot after migration. +- `LAUNCH_READINESS.md`: paid pilot / Team / Enterprise evaluation path can inform future pilot readiness, but old terms must be removed. +- `docs/public-vs-pilot.md`: useful public/pilot boundary pattern. +- `tools/pilot-readiness.py`: potential seed for paid workflow-fit assessment, but not safe as-is. +- `README.md` and `COMMERCIAL_BOUNDARY.md`: current funnel language includes paid pilot and support concepts. + +Obsolete Pilot Access Engine infrastructure: + +- No implementation of scoped key generation or Pilot Access Engine was found. +- `README.md`, `SPEC.md`, `COMMERCIAL_BOUNDARY.md`, `PILOT_ACCESS.md`, `ADOPTION.md`, `docs/glossary.md`, `openapi/README.md`, `validator/README.md`, `cli/README.md`, `worker-reference/README.md`, and `tools/check-public-task-repo.sh` contain active Pilot Access Engine messaging. + +Private operational records: + +- None found in tracked files. +- No pilot submissions, private records, customer workflows, or production scoped keys were found. + +Public funnel content: + +- `README.md`: "Request Pilot Access: pilots@passpod.io". +- `PILOT_ACCESS.md`: pilot access upgrade path. +- `SECURITY.md`: same pilot mailbox used for security concerns. +- `openapi/passpod-task.public.yaml`: contact is `Passpod Pilot Access`. +- `tools/pilot-readiness.py`: prints next step to request Pilot Access. + +Generic reusable intake or workflow code: + +- `tools/pilot-readiness.py`: reads arbitrary receipt JSON and produces a readiness score. It does not store data and has no CI dependency, but scoring criteria are legacy and should be redesigned before reuse. + +## 11. Public-surface contamination map + +Public surfaces found: + +- GitHub repository identity: remote `edidx/passpod-task`, branch `main`. +- README badge: links to `https://github.com/edidx/passpod-task/actions/workflows/validate.yml`. +- Public docs: all top-level Markdown and `docs/*.md`. +- Public examples: `examples/*.receipt.json`. +- Public schema URL: `https://passpod.io/schemas/trust-action-receipt.schema.json`. +- Public OpenAPI placeholder server: `https://api.passpod.example`. +- Contact email: `pilots@passpod.io`. + +No HTML pages, website routing files, app navigation files, CTAs in code, Cloudflare deployment files, package metadata, or API portal implementation were found in this repository. + +Contaminating terms found on public surfaces: + +- `Passpod TASK Core` +- `TASK check` +- `TASK decision` +- `Sensitive Action Control` +- `No receipt, no sensitive action` +- `Passpod Hub` +- `Control Packs` +- `AgentTrust` +- `Remote Worker Trust` +- `Remote Worker TrustPass` +- `Pilot Access Engine` +- `Live Control API` +- `Kill-State API` +- `allow`, `deny`, `freeze`, `revoke` as central decision model +- `DIDX` + +Terms not found as active literals: + +- `TASK Guard` +- `TASK modules` +- `Passpod Standard` as a named active architecture +- `PROPOSE` +- `CHALLENGE` +- `AGREE` +- `CLOSE` +- `Passpod SDK` +- `Reference Profiles` + +## 12. Dependency and breakage risks + +Tests and CI: + +- `bash tools/check-public-task-repo.sh` passes today, but it validates the old TASK public repo model. +- `.github/workflows/validate.yml` installs `requirements.txt`, JSON-parses the schema and three example receipts, then runs `tools/check-public-task-repo.sh`. +- Removing or renaming `README.md`, `SPEC.md`, `PILOT_ACCESS.md`, `ADOPTION.md`, `SECURITY.md`, `CONTRIBUTING.md`, `GOVERNANCE.md`, `VERSIONING.md`, `COMMERCIAL_BOUNDARY.md`, `requirements.txt`, schema, `examples/remote-worker.receipt.json`, `examples/README.md`, OpenAPI, `openapi/README.md`, `validator/README.md`, `cli/README.md`, `worker-reference/README.md`, selected `docs/*.md`, or `tools/validate-receipts.py` will break the current gate. +- Removing or changing old required phrases in `README.md`, `SPEC.md`, `ADOPTION.md`, `COMMERCIAL_BOUNDARY.md`, `docs/glossary.md`, `PILOT_ACCESS.md`, `LAUNCH_READINESS.md`, `cli/README.md`, `worker-reference/README.md`, or `openapi/README.md` will break the current gate until the gate is migrated. + +Imports and runtime: + +- `tools/validate-receipts.py` imports `json`, `pathlib`, and `jsonschema`. +- `tools/pilot-readiness.py` imports `json`, `sys`, and `pathlib`. +- No application imports, SDK package exports, package manager scripts, or API server routes were found. + +Routes and API shapes: + +- OpenAPI defines `/v1/spec`, `/v1/receipts/validate`, and `/v1/receipts/{receipt_id}`. +- No implemented HTTP routes were found. +- If external docs or clients use this OpenAPI file, migration could break expectations even though this repo has no runtime route implementation. + +Links and navigation: + +- README links to `SPEC.md`, schema, OpenAPI, examples README, validator README, `PILOT_ACCESS.md`, `COMMERCIAL_BOUNDARY.md`, `ROADMAP.md`, and `FUNDING_USE.md`. +- OpenAPI metadata references `LICENSE`. +- Several READMEs instruct `python3 -m pip install -r requirements.txt` and `python3 tools/validate-receipts.py`. + +Deployment: + +- No Cloudflare, Wrangler, Pages, Vercel, Netlify, Docker, GitLab CI, package deployment, or public website deployment files were found. +- Cloudflare deployment breakage risk in this repo is currently none observed. + +Package exports: + +- No `package.json`, lockfile, SDK package, package exports, npm config, or Python package metadata were found. + +Local development commands: + +- `python3 tools/validate-receipts.py` passes. +- `bash tools/check-public-task-repo.sh` passes. +- These commands are tied to old terminology and fixtures. + +## 13. Sensitive/private data findings + +Data categories observed: + +- Demo receipt fixtures: `examples/*.receipt.json` contain demo actors, demo subjects, static demo timestamps, and `demo-signature-not-production`. +- Contact email: `pilots@passpod.io` appears in public docs, OpenAPI contact, and tooling output. +- Ownership/legal labels: `@edidx` in CODEOWNERS and DIDX in governance/license/docs. +- No real user information found. +- No pilot submissions found. +- No secrets, tokens, credentials, passwords, production keys, or private key blocks found. +- No private operational records found. +- No generated artifacts found except ordinary source/documentation files. +- No `.env`, `.dev.vars`, Wrangler state, deployment secrets, or package lock secrets found in this repo. + +Remediation requirements: + +- Keep the dangerous-pattern checks from `tools/check-public-task-repo.sh` or an equivalent reset gate. +- Treat `pilots@passpod.io`, `@edidx`, and DIDX labels as public operational/legal labels requiring owner confirmation before changing. +- Do not add real pilot data or workflow-fit assessment records to this public repo. + +## 14. Recommended cleanup order + +1. Update the validation gate design first, because the current gate enforces old architecture terms and old required files. +2. Migrate the public entry and core doctrine together: `README.md`, `SPEC.md`, `docs/glossary.md`, and `COMMERCIAL_BOUNDARY.md`. +3. Migrate the schema and example fixtures together so CI always has a coherent validation target. +4. Migrate OpenAPI only after deciding whether the reset architecture exposes public API routes or relies on SDK/reference validation. +5. Migrate pilot funnel language separately from obsolete Pilot Access Engine language; keep legitimate paid-pilot concepts. +6. Re-run CI/local checks after each bounded group; do not archive or delete active fixtures until replacements are wired into the gate. + +## 15. Proposed bounded next pass + +Exactly one bounded next pass is recommended: + +Draft a public-surface and gate migration plan for the reset architecture, limited to `README.md`, `SPEC.md`, `docs/glossary.md`, `PILOT_ACCESS.md`, `COMMERCIAL_BOUNDARY.md`, `schemas/trust-action-receipt.schema.json`, `examples/`, `openapi/passpod-task.public.yaml`, `.github/workflows/validate.yml`, and `tools/check-public-task-repo.sh`. The pass should produce a proposed mapping and test plan only; it should not rewrite files until the mapping is approved. + +## 16. Files that must not be touched without explicit approval + +Do not touch these without explicit approval: + +- `README.md` +- `SPEC.md` +- `COMMERCIAL_BOUNDARY.md` +- `PILOT_ACCESS.md` +- `ADOPTION.md` +- `ROADMAP.md` +- `FUNDING_USE.md` +- `GOVERNANCE.md` +- `SECURITY.md` +- `LICENSE` +- `schemas/trust-action-receipt.schema.json` +- `openapi/passpod-task.public.yaml` +- `examples/agent-freeze.receipt.json` +- `examples/refund-review.receipt.json` +- `examples/remote-worker.receipt.json` +- `.github/workflows/validate.yml` +- `.github/CODEOWNERS` +- `tools/check-public-task-repo.sh` +- `tools/validate-receipts.py` +- `tools/pilot-readiness.py` + +Reason: these files carry public positioning, legal/stewardship labels, active validation behavior, CI behavior, active example fixtures, or pilot/security funnel language. + +## Checks and searches performed + +Commands and checks performed: + +- `git status --short` +- `git rev-parse --show-toplevel` during repo discovery +- `git ls-files` +- `git branch --show-current` +- `git remote -v` +- `rg --hidden --files -g '!*.pyc' -g '!__pycache__' -g '!.git'` +- `find . -maxdepth 3 -type d -not -path './.git*'` +- `find . -type d -empty -not -path './.git*'` +- `find . -maxdepth 3 -type f` for package, deployment, HTML, script, and config files +- `file` over non-git files +- `wc -l` over non-git files +- Full content reads of top-level Markdown, `docs/*.md`, `.github/*`, schema JSON, example JSON, OpenAPI YAML, validator docs, CLI docs, worker reference docs, and tools +- Targeted `rg` searches for TASK, TASK Guard, TASK modules, Pilot Access Engine, Control Packs, AgentTrust, Passpod Hub, TASK Core, Live Control API, Kill-State, Sensitive Action Control, allow, deny, freeze, revoke, Pilot Access, pilot, Remote Worker, PassPal, DIDX, console, API portal, Passpod Protocol, Passpod Standard, Handshake, SDK, Reference Profiles, Passpod Pilot, TrustPass, Trust Action Receipt, and No receipt +- Targeted `rg` searches for links, route paths, operation IDs, CI `uses`/`run`, Python commands, schema/example/OpenAPI/validator references, deployment terms, package terms, and imports +- Targeted `rg` searches for sensitive/private data markers: secret assignments, private keys, live keys, AWS key pattern, token, credential, password, customer, email, pilot submissions, real customer, scoped key, `.dev.vars`, Wrangler, and Cloudflare +- `python3 tools/validate-receipts.py` +- `bash tools/check-public-task-repo.sh` + +Observed validation output: + +- `python3 tools/validate-receipts.py`: passed for all three demo receipts. +- `bash tools/check-public-task-repo.sh`: passed and printed `Public TASK repo gate passed`; this is a pass of the old TASK gate, not evidence of reset alignment. + +## Uncertainties + +- Whether the GitHub repository name `edidx/passpod-task` will be renamed, archived, or kept as a historical public repo is a strategic decision not inferable from local files. +- Whether DIDX remains the legal/stewardship label under the reset architecture needs human/legal confirmation. +- Whether `pilots@passpod.io` should remain the pilot and security contact needs operational confirmation. +- Whether `Remote Worker` should become a canonical Reference Profile or be archived is not inferable from this repo alone. +- Whether external clients use `openapi/passpod-task.public.yaml` is not inferable from local imports. +- Empty local directories `packages/validator/`, `spec/`, and `src/` are not tracked by git; their intended purpose is unknown. + diff --git a/docs/PROFILES.md b/docs/PROFILES.md new file mode 100644 index 0000000..f8a79c7 --- /dev/null +++ b/docs/PROFILES.md @@ -0,0 +1,167 @@ +# Passpod Profiles + +## Status + +This document defines the conceptual model for Passpod Profiles. + +Profiles are first-class architecture. Profiles specialize Passpod. Profiles do not redefine Passpod. + +This document does not define JSON, schemas, SDK classes, APIs, storage, cryptography, transports, or implementation. + +## Purpose + +Profiles exist so Passpod can adapt to different domains while preserving a single Standard and Handshake Protocol. + +A profile gives domain-specific meaning to participant roles, evidence expectations, terminology, extensions, workflow guidance, and terminal interpretation. It allows a domain to be precise without changing the core architecture. + +Profiles make specialization explicit. They prevent domain assumptions from silently becoming universal Passpod semantics. + +## Relationship to Other Documents + +Profiles are subordinate to the Standard, Protocol, State Model, Message Model, and Conformance documents. + +Profiles may specialize those documents for a domain, but they must preserve their normative meaning. + +### Standard + +The Standard defines Passpod semantics. + +A profile may narrow or clarify Standard semantics for a domain, but it must not replace the Standard or create conflicting semantics. + +### Protocol + +The Protocol defines the canonical handshake: + +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` + +A profile may guide how a domain uses the handshake, but it must not redefine the protocol messages or the protocol's transport-neutral character. + +### State Model + +The State Model defines conceptual message and handshake lifecycles. + +A profile may interpret terminal outcomes or add domain guidance for lifecycle usage, but it must not replace append-only history, immutable accepted messages, or closure as the end of active negotiation. + +### Message Model + +The Message Model defines conceptual relationships between messages, handshakes, participants, profiles, evidence, references, versions, and extensions. + +A profile may add domain-specific expectations for those relationships, but it must not prescribe core representation details unless it is explicitly defining a profile-level convention. + +### Conformance + +The Conformance document defines how artifacts align with Passpod. + +A profile may add profile-specific conformance expectations, but it must preserve core conformance and must not make profile-specific behavior appear universal. + +## Profile Concept + +A Profile is a domain-specific specialization of Passpod. + +A profile describes how the Passpod Standard, Handshake Protocol, State Model, and Message Model apply in a particular domain or workflow context. + +Illustrative domains may include: + +- employment; +- banking; +- procurement; +- healthcare; +- education; +- digital identity. + +These are illustrative only. This document does not prescribe any active profile. + +## What Profiles MAY Define + +Profiles MAY define domain-specific guidance and constraints, conceptually including: + +- participant roles; +- evidence expectations; +- terminology; +- domain-specific extensions; +- version expectations; +- workflow guidance; +- terminal outcome interpretation; +- optional constraints. + +Profile definitions must remain compatible with the active Passpod architecture. + +## What Profiles MUST NOT Redefine + +Profiles MUST NOT redefine: + +- `PROPOSE`; +- `CHALLENGE`; +- `AGREE`; +- `CLOSE`; +- append-only history; +- immutable accepted messages; +- Standard semantics; +- Protocol semantics. + +A profile that redefines the core architecture is not a conformant Passpod Profile. + +## Profile Lifecycle + +Profile lifecycle stages are conceptual governance stages, not implementation states. + +### Draft + +A Draft profile is exploratory and not yet approved as a stable specialization. + +### Review + +A Review profile is being evaluated for semantic compatibility, domain usefulness, and conformance with the active architecture. + +### Approved + +An Approved profile is accepted as a conformant specialization for its stated domain or workflow context. + +### Deprecated + +A Deprecated profile remains historically understandable but is no longer recommended for new use. + +### Archived + +An Archived profile is preserved for historical, migration, or audit purposes and is outside active use. + +## Profile Versioning + +Profiles evolve independently. + +The Standard, Protocol, Message Model, Conformance model, and individual Profiles may have different version histories. + +Profile versioning supports compatibility, migration, and interpretation. This document does not prescribe version syntax. + +## Profile Extensions + +Profiles may introduce compatible extensions. + +Profile extensions may add domain detail, evidence conventions, participant role distinctions, workflow guidance, or optional constraints. + +Extensions must preserve semantic compatibility with the Standard, Protocol, State Model, Message Model, and Conformance model. + +An extension must not use profile specificity to redefine Passpod itself. + +## Future Reference Profiles + +Future reference profiles may exist. + +Reference profiles are intentionally outside this document. This document defines the profile model only; it does not create actual profiles or select active profile domains. + +## Non-goals + +This document does not define: + +- schemas; +- APIs; +- SDKs; +- validators; +- CLI; +- storage; +- signatures; +- certification; +- implementation. + diff --git a/docs/PROTOCOL.md b/docs/PROTOCOL.md new file mode 100644 index 0000000..aa38dd9 --- /dev/null +++ b/docs/PROTOCOL.md @@ -0,0 +1,112 @@ +# Passpod Handshake Protocol + +## Status + +This document describes the conceptual Passpod Handshake Protocol. + +The protocol is transport-neutral. It does not define individual fields, schemas, JSON, APIs, transports, validators, or SDK internals. + +## Handshake Concept + +A handshake is an append-only negotiation between participants. + +The canonical handshake flow is: + +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` + +The flow creates a shared negotiation history. Each step adds meaning to the handshake without rewriting earlier messages. + +## Participants + +A participant is an actor, system, organization, profile-defined role, or other party that takes part in a handshake. + +Participants may initiate proposals, raise challenges, express agreement, or close the handshake. Profiles may specialize participant roles, but the protocol does not require a particular identity system, authorization system, transport, or runtime. + +## Message Relationships + +Protocol messages are related by their position in a handshake. + +A proposal begins a handshake. A challenge responds to a proposal or to prior negotiation context. An agreement records accepted negotiation meaning. A closure completes the handshake and records its terminal outcome. + +Messages do not stand alone as isolated facts. Their meaning comes from their relationship to the handshake and to the messages that precede them. + +## Parent References + +Messages after the initial proposal refer back to earlier handshake context. + +Parent references preserve negotiation lineage. They allow participants to understand what a message is responding to, what it depends on, and where it belongs in the handshake history. + +This document does not define how parent references are represented. + +## Handshake Identifier + +A handshake has a stable identifier that lets participants recognize which messages belong to the same negotiation. + +The identifier provides continuity across the handshake. It is not a transport requirement and this document does not define its format. + +## Append-only Philosophy + +The handshake history is append-only. + +Participants add messages to advance negotiation. They do not rewrite accepted prior messages. Corrections, refinements, replacements, or withdrawals are expressed by adding later messages that clarify the negotiation history. + +Append-only history supports reviewability, shared context, and profile-level conformance. + +## Immutable Messages + +Once accepted into a handshake history, a message is immutable. + +Immutability means the message remains stable as part of the negotiation record. Later messages may supersede, reject, qualify, or close prior negotiation meaning, but they do not mutate the prior message itself. + +## Negotiation Flow + +The protocol flow is intentionally small: + +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` + +Profiles may allow repeated negotiation turns, such as additional challenges or revised proposals, as long as the handshake remains append-only and eventually reaches closure. + +## PROPOSE + +`PROPOSE` begins or advances a negotiation by stating what a participant wants to establish. + +A proposal creates the initial subject of negotiation. It gives other participants something to examine, question, refine, or accept. + +## CHALLENGE + +`CHALLENGE` responds to a proposal or prior negotiation context. + +A challenge asks for clarification, evidence, constraint, revision, qualification, or other negotiation work before agreement. A challenge does not close the handshake by itself. + +## AGREE + +`AGREE` records that the relevant participants accept the negotiated meaning for the handshake context. + +Agreement is not necessarily universal across every possible party or future use. It is scoped to the handshake and any applicable profile semantics. + +## CLOSE + +`CLOSE` completes the handshake. + +Closure records that the negotiation has reached a terminal outcome. A closed handshake is no longer active negotiation, though later systems or profiles may refer to the closed record. + +## Transport Neutrality + +The protocol does not depend on HTTP, queues, email, files, ledgers, databases, blockchains, wallets, browsers, or any other transport. + +A transport can carry protocol messages, but the transport is not the protocol. + +## Relationship to the Standard, SDK, and Profiles + +The Standard defines protocol semantics. + +The SDK implements the protocol. + +Profiles specialize the protocol. + +The protocol remains the shared negotiation model across those layers. + diff --git a/docs/SPECIFICATION_FREEZE_REPORT.md b/docs/SPECIFICATION_FREEZE_REPORT.md new file mode 100644 index 0000000..ac123e9 --- /dev/null +++ b/docs/SPECIFICATION_FREEZE_REPORT.md @@ -0,0 +1,344 @@ +# Passpod Specification Freeze Report + +## Executive Summary + +The Passpod conceptual specification is internally consistent enough to freeze as `Passpod Specification v0.1`. + +Reviewed documents: + +- `docs/STANDARD.md` +- `docs/PROTOCOL.md` +- `docs/STATE-MODEL.md` +- `docs/TERMINOLOGY.md` +- `docs/MESSAGE-MODEL.md` +- `docs/CONFORMANCE.md` +- `docs/PROFILES.md` + +No major inconsistencies were found. The documents consistently preserve the core architecture: + +```text +Passpod Standard +-> Passpod Handshake Protocol +-> State Model +-> Message Model +-> Profiles +-> Conformance +``` + +The Standard remains the semantic authority. The Protocol preserves `PROPOSE -> CHALLENGE -> AGREE -> CLOSE`. The State Model preserves append-only history, immutable accepted messages, and terminal closure. Profiles remain subordinate specializations. Conformance evaluates alignment and does not become the source of protocol semantics. + +## Architecture Maturity Score + +Score: 91 / 100 + +Rationale: + +- Core terminology is defined once and reused consistently. +- Layer boundaries are mostly clean. +- Legacy terminology is isolated to the archived terminology section. +- Protocol meanings are stable across documents. +- The implementation boundary is consistently deferred. +- Minor refinement is still needed around cross-document references, profile lifecycle governance, and whether conformance is a layer or cross-cutting audit model. + +## Strengths + +- `docs/STANDARD.md` clearly establishes the Standard as the semantic authority and excludes schemas, APIs, SDK code, validators, transports, storage, and implementation details. +- `docs/PROTOCOL.md` cleanly defines the handshake concept, participants, parent references, handshake identifier, append-only history, immutable messages, and negotiation flow without defining fields or schemas. +- `docs/STATE-MODEL.md` preserves lifecycle discipline and explicitly makes closure terminal. +- `docs/TERMINOLOGY.md` gives normative meanings for the core concepts and keeps archived legacy terminology outside the active architecture. +- `docs/MESSAGE-MODEL.md` explains conceptual message relationships while keeping representation unspecified. +- `docs/CONFORMANCE.md` correctly states that semantic conformance comes before implementation conformance and that validators must not become the source of meaning. +- `docs/PROFILES.md` defines profiles as first-class architecture while preserving their subordinate relationship to core documents. + +## Weaknesses + +- Cross-document references are mostly conceptual rather than explicit. This is acceptable for v0.1, but future implementation work will need a traceable map from SDK behavior back to the normative documents. +- `Conformance` is described both as a document profiles are subordinate to and as an evaluator of alignment. This is not contradictory, but it makes conformance slightly cross-cutting rather than a simple downstream layer. +- `Reference Profiles` appears in the architecture list, while `Profile` is the primary normative term. This is understandable, but future docs should maintain a clear distinction between the general Profile model and future Reference Profiles. +- `Passpod Pilot` is defined at a high level in `STANDARD.md` and `TERMINOLOGY.md`, but it is not part of the reviewed layer sequence beyond implementation feedback and workflow-fit evaluation. + +## Minor Inconsistencies + +1. `Profile` and `Reference Profiles` + + `docs/TERMINOLOGY.md` lists `Reference Profiles` as part of the active architecture, while most normative definitions use `Profile`. `docs/PROFILES.md` explains future reference profiles but intentionally does not create them. This is a minor naming distinction, not a semantic conflict. + +2. Conformance as layer versus cross-cutting model + + The requested architecture order places Conformance after Profiles. `docs/PROFILES.md` says Profiles are subordinate to the Conformance document, while `docs/CONFORMANCE.md` says conformance evaluates artifacts against the Standard, Protocol, Message Model, and Profiles. This is not a major issue because `docs/CONFORMANCE.md` explicitly preserves the Standard as semantic authority, but implementation planning should treat conformance as an evaluation model rather than a source of domain semantics. + +3. State Model and Protocol repeated-turn wording + + `docs/PROTOCOL.md` allows repeated negotiation turns such as additional challenges or revised proposals. `docs/STATE-MODEL.md` allows `[Proposed] -> [Challenged] -> [Proposed]` and `[Challenged] -> [Challenged]`. These are consistent, but the exact boundary of repeated turns remains conceptual and profile-governed. + +## Major Inconsistencies + +None found. + +## Terminology Audit + +Every reviewed core concept has one normative meaning or a clearly subordinate conceptual elaboration. + +Core terms: + +- `Passpod`: defined in `docs/TERMINOLOGY.md` as the overall architecture for transport-neutral trust negotiation. +- `Passpod Standard`: defined in `docs/TERMINOLOGY.md` and elaborated in `docs/STANDARD.md` as the semantic authority. +- `Handshake Protocol`: defined as the canonical transport-neutral flow `PROPOSE -> CHALLENGE -> AGREE -> CLOSE`. +- `Handshake`: defined as a bounded negotiation history between participants. +- `Message`: defined as an immutable unit of handshake communication once accepted into handshake history. +- `Participant`: defined as a party that takes part in a handshake. +- `Profile`: defined as domain-specific specialization that preserves core protocol meanings. +- `Evidence`: defined as information introduced to support, question, qualify, or resolve negotiation. +- `Reference`: defined as a relationship from one part of a handshake to another piece of handshake context. +- `Extension`: defined as compatible specialization without redefining core architecture. +- `Conformance`: defined as alignment with the Standard, Protocol, and any declared profile. + +Duplicates found: + +- No conflicting duplicate normative definitions were found. +- Several concepts are repeated in subordinate documents, but the repetitions preserve the same meaning. + +Ambiguity found: + +- `Reference Profiles` versus `Profile` should remain carefully distinguished in future implementation work. +- `Version association` is referenced conceptually in the Message Model and Profiles, but version governance is not yet normatively assigned to a specific document. + +Conflicting definitions found: + +- None. + +## Layer Separation Audit + +Standard: + +- Defines semantics and architectural scope. +- Does not define messages, schemas, APIs, SDK code, validators, transports, or storage. + +Protocol: + +- Defines the transport-neutral handshake flow and message meanings. +- Does not define fields, schemas, JSON, APIs, transports, validators, or SDK internals. + +State Model: + +- Defines conceptual lifecycle states and transitions. +- Does not define implementation state, storage, schemas, APIs, or SDK internals. + +Message Model: + +- Defines conceptual message structure and relationships. +- Keeps representation unspecified and does not require JSON. + +Profiles: + +- Specialize Passpod for domains. +- Must not redefine Standard or Protocol semantics. + +Conformance: + +- Defines alignment requirements. +- Does not become the source of protocol semantics. + +Architectural overlap: + +- No blocking overlap found. +- Conformance is cross-cutting by nature and should be treated as an evaluation layer, not as a semantic replacement for the Standard. + +## Cross-reference Audit + +Correct references: + +- Standard references Protocol, SDK, Profiles, Passpod Pilot, conformance, extensions, and archived terminology boundaries. +- Protocol references Standard, SDK, Profiles, parent references, handshake identifier, append-only history, and immutable messages. +- State Model references profile-level repeated negotiation and terminal meanings. +- Terminology references Standard, Protocol, SDK, Reference Profiles, Pilot, active concepts, and archived legacy terms. +- Message Model references handshakes, participants, profiles, evidence, references, versions, and extensions. +- Conformance references Standard, Protocol, Message Model, Profiles, SDK, Validators, CLI, and Documentation. +- Profiles references Standard, Protocol, State Model, Message Model, and Conformance. + +Missing references: + +- `docs/STATE-MODEL.md` does not explicitly state that it is subordinate to the Standard and Protocol, though its content is consistent with that hierarchy. +- `docs/MESSAGE-MODEL.md` does not explicitly state its relationship to `docs/STATE-MODEL.md`, though it preserves compatible lifecycle assumptions. +- `docs/CONFORMANCE.md` does not list `State Model` in every future conformance class, though it does preserve append-only history and immutable accepted messages. + +Circular dependencies: + +- No harmful circular dependencies found. +- `Profiles` and `Conformance` refer to each other. This is acceptable if Conformance remains an evaluator and Profiles remain domain specializations. + +Inconsistent terminology: + +- No active inconsistent terminology found. + +## Legacy Contamination Audit + +Archived legacy terms found only in `docs/TERMINOLOGY.md`: + +- `TASK Guard` +- `TASK Core` +- `Passpod Hub` +- `AgentTrust` +- `Control Packs` +- `Pilot Access Engine` +- `Sensitive Action Control` +- `Trust Action Receipt as the primary protocol object` +- `Kill-State` + +Active usage: + +- None found in the reviewed canonical documents. + +Legacy contamination result: + +- Pass. Archived terminology appears only as archived terminology. + +## Protocol Consistency Audit + +The canonical sequence is consistent: + +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` + +Message meanings are preserved: + +- `PROPOSE` introduces or advances what a participant wants to establish. +- `CHALLENGE` asks for clarification, evidence, constraint, revision, qualification, or other negotiation work. +- `AGREE` records accepted negotiation meaning within handshake scope. +- `CLOSE` ends active negotiation and records terminal outcome. + +No document changes or contradicts these meanings. + +## State Consistency Audit + +Append-only history: + +- Preserved in Standard, Protocol, State Model, Message Model, Conformance, and Profiles. + +Immutable accepted messages: + +- Preserved in Standard, Protocol, State Model, Message Model, Conformance, and Profiles. + +Closure is terminal: + +- Preserved in Protocol, State Model, Conformance, and Profiles. + +Contradictions: + +- None found. + +## Profile Consistency Audit + +Profiles remain subordinate to: + +- Standard +- Protocol +- State Model +- Message Model +- Conformance + +Profiles may define participant roles, evidence expectations, terminology, extensions, version expectations, workflow guidance, terminal outcome interpretation, and optional constraints. + +Profiles must not redefine: + +- `PROPOSE` +- `CHALLENGE` +- `AGREE` +- `CLOSE` +- append-only history +- immutable accepted messages +- Standard semantics +- Protocol semantics + +Contradictions: + +- None found. + +## Conformance Consistency Audit + +Conformance does not become the source of semantics. + +The Standard remains authoritative: + +- `docs/STANDARD.md` states the Standard defines Passpod semantics. +- `docs/CONFORMANCE.md` states Standard conformance means aligning with the Passpod Standard as the semantic authority. +- Validator conformance explicitly says validators must not make implementation assumptions normative unless those assumptions are defined by applicable normative material. + +Contradictions: + +- None found. + +## Missing Concepts + +The following concepts are referenced repeatedly but are not yet fully normatively defined: + +- `Version association` +- `Version expectations` +- `Version histories` +- `Passpod Pilot` +- `Reference Profiles` +- `Workflow fit` +- `Terminal outcome interpretation` +- `Evidence expectations` +- `Profile lifecycle governance` +- `Review`, `Approved`, `Deprecated`, and `Archived` authority for profiles +- `Recipient` +- `Sender` +- `Timestamp concept` +- `Handshake identifier` +- `Message identity` + +These gaps are acceptable for a conceptual freeze because the documents intentionally avoid schemas, storage, identity systems, cryptography, and implementation detail. + +## Open Questions + +- Who has authority to approve a Profile lifecycle transition from Review to Approved? +- Which Reference Profile should be first after SDK core implementation exists? +- How should version association be represented once schemas or SDK code exist? +- Which terminal outcomes are universal versus profile-specific? +- How much evidence expectation belongs in a profile before it becomes implementation detail? + +## Recommended Implementation Readiness + +Recommendation: ready for bounded implementation. + +The conceptual specification is mature enough for a minimal implementation phase focused on the transport-neutral SDK core. Implementation should not begin by designing schemas, APIs, validators, CLI, storage, signatures, or cryptography. + +Implementation should preserve: + +- Standard as semantic authority; +- Protocol as `PROPOSE -> CHALLENGE -> AGREE -> CLOSE`; +- append-only handshake history; +- immutable accepted messages; +- terminal closure; +- profile compatibility without profile implementation. + +## Recommended Repository Tag + +Recommended tag: + +```text +Passpod Specification v0.1 (Frozen) +``` + +## Final Recommendation + +Proceed with exactly one next implementation phase: + +Build a minimal transport-neutral SDK core that models handshake identity, message identity, immutable accepted messages, parent references, append-only history, and allowed `PROPOSE -> CHALLENGE -> AGREE -> CLOSE` lifecycle transitions, with focused tests and without schemas, APIs, transports, storage, signatures, cryptography, validators, CLI, examples, or profile implementations. + +## Validation + +Requested validation command: + +```text +git status --short +``` + +The only file newly created by this freeze audit pass is: + +```text +docs/SPECIFICATION_FREEZE_REPORT.md +``` + diff --git a/docs/STANDARD.md b/docs/STANDARD.md new file mode 100644 index 0000000..e56006e --- /dev/null +++ b/docs/STANDARD.md @@ -0,0 +1,101 @@ +# Passpod Standard + +## Status + +This document establishes the purpose and semantic boundary of the Passpod Standard. + +The Standard defines what Passpod means at the architecture level. It does not define message formats, JSON structures, APIs, schemas, validators, SDK code, or transport bindings. + +## Scope + +The Passpod Standard defines the semantics for structured trust negotiation between participants. + +The active architecture consists of: + +- Passpod Standard +- Passpod Handshake Protocol +- Passpod SDK +- Reference Profiles +- Passpod Pilot + +The Standard defines the meaning of the architecture and the responsibilities of each layer. It is the source of semantic alignment for the protocol, SDK, profiles, and pilot work. + +## Objectives + +The objectives of the Standard are to: + +- define the core Passpod concepts in transport-neutral terms; +- define the relationship between proposals, challenges, agreements, and closures; +- support interoperable implementations without prescribing a single runtime; +- allow profiles to specialize Passpod for specific domains without changing the core semantics; +- provide a conformance philosophy for implementations, profiles, documentation, and pilots; +- keep public semantics distinct from private implementation and operational detail. + +## Non-objectives + +The Standard does not: + +- define individual message fields; +- define JSON or any other serialization format; +- define schemas; +- define HTTP routes, APIs, webhooks, or transports; +- define SDK code or package structure; +- define validators or conformance test suites; +- prescribe storage, signing, identity, payment, deployment, or hosting systems; +- make any archived legacy terminology part of the active architecture. + +## Relationship with the Protocol + +The Standard defines the semantics. The Handshake Protocol expresses those semantics as a transport-neutral negotiation flow. + +The canonical protocol flow is: + +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` + +The Standard explains what the protocol is for. The protocol explains how participants move through a handshake. The Standard remains higher-level than the protocol and does not define protocol message formats. + +## Relationship with the SDK + +The SDK implements the protocol. + +An SDK may help participants create, interpret, validate, transmit, store, or inspect protocol messages, but the Standard does not prescribe SDK internals. SDK behavior is conformant when it preserves the semantics of the Standard and the ordering discipline of the Handshake Protocol. + +## Relationship with Profiles + +Profiles specialize the protocol for a specific domain, workflow, ecosystem, or trust context. + +A profile may define domain-specific expectations, evidence conventions, extension rules, terminology, or participant roles. A profile must not redefine the core meaning of `PROPOSE`, `CHALLENGE`, `AGREE`, or `CLOSE`. + +Profiles are subordinate to the Standard. They may narrow or extend usage, but they must preserve protocol semantics. + +## Relationship with Passpod Pilot + +Passpod Pilot is the controlled path for evaluating workflow fit against the Standard, the protocol, the SDK, and relevant profiles. + +Pilot work may produce operational knowledge, profile candidates, implementation feedback, or conformance questions. Pilot work does not change the Standard unless those learnings are intentionally incorporated into a later Standard revision. + +## Conformance Philosophy + +Conformance is semantic before it is technical. + +A conformant Passpod implementation must preserve: + +- the distinction between the Standard, protocol, SDK, profiles, and pilot work; +- the canonical handshake progression; +- transport neutrality; +- append-only negotiation history; +- immutable accepted messages; +- profile specialization without core semantic drift. + +Conformance should be testable, but this document does not define tests. + +## Extension Philosophy + +Passpod is designed to allow extensions without fragmenting the core architecture. + +Extensions may add domain detail, evidence conventions, profile rules, transport bindings, or implementation capabilities. Extensions must not replace the protocol flow, redefine core terms, or reintroduce archived legacy product concepts as active architecture. + +An extension is acceptable when it clarifies a specialized use while preserving the Standard. + diff --git a/docs/STATE-MODEL.md b/docs/STATE-MODEL.md new file mode 100644 index 0000000..74351b3 --- /dev/null +++ b/docs/STATE-MODEL.md @@ -0,0 +1,128 @@ +# Passpod State Model + +## Status + +This document defines conceptual lifecycle states for Passpod messages and handshakes. + +It does not define implementation details, message fields, schemas, transports, APIs, storage systems, validators, or SDK internals. + +## Message Lifecycle + +A message lifecycle describes how a single protocol message becomes part of a handshake history. + +Conceptual lifecycle: + +```text +[Composed] + | + v +[Emitted] + | + v +[Accepted into handshake history] + | + v +[Referenced by later message] + | + v +[Preserved as immutable history] +``` + +A message that is not accepted into the handshake history remains outside the authoritative negotiation record. + +Conceptual rejection path: + +```text +[Composed] + | + v +[Emitted] + | + v +[Not accepted into handshake history] +``` + +## Handshake Lifecycle + +A handshake lifecycle describes the state of the negotiation as a whole. + +Conceptual lifecycle: + +```text +[Not started] + | + v +[Proposed] + | + v +[Challenged] + | + v +[Agreed] + | + v +[Closed] +``` + +Negotiation may repeat before agreement when a profile allows additional turns. + +Conceptual repeated negotiation: + +```text +[Proposed] -> [Challenged] -> [Revised negotiation context] + ^ | + | v + +--------- [Further challenge] <-+ +``` + +## Allowed Transitions + +The canonical transition path is: + +```text +[Not started] -> [Proposed] -> [Challenged] -> [Agreed] -> [Closed] +``` + +Profiles may allow repeated proposal and challenge turns: + +```text +[Proposed] -> [Challenged] -> [Proposed] +[Challenged] -> [Challenged] +[Agreed] -> [Closed] +``` + +Closure is terminal: + +```text +[Closed] -x-> [Proposed] +[Closed] -x-> [Challenged] +[Closed] -x-> [Agreed] +``` + +The state model does not require every implementation to expose state names directly. The requirement is conceptual conformance to the handshake lifecycle. + +## Terminal Outcomes + +A handshake reaches a terminal outcome when it is closed. + +Conceptual terminal outcomes: + +```text +[Agreed] -> [Closed: completed] +[Challenged] -> [Closed: unresolved] +[Proposed] -> [Closed: withdrawn] +[Proposed] -> [Closed: declined] +``` + +Profiles may define more specific terminal meanings, but they must preserve the concept that `CLOSE` ends active negotiation. + +## State Principles + +The state model follows these principles: + +- accepted messages are immutable; +- handshake history is append-only; +- later messages may qualify earlier messages; +- closure ends active negotiation; +- profiles may specialize state meaning without replacing the canonical protocol flow. + diff --git a/docs/TERMINOLOGY.md b/docs/TERMINOLOGY.md new file mode 100644 index 0000000..44f10e7 --- /dev/null +++ b/docs/TERMINOLOGY.md @@ -0,0 +1,176 @@ +# Passpod Terminology + +## Status + +This document defines active Passpod terminology and archived legacy terminology. + +Active terminology belongs to the canonical architecture: + +- Passpod Standard +- Passpod Handshake Protocol +- Passpod SDK +- Reference Profiles +- Passpod Pilot + +Archived terminology is preserved for historical and migration context, but it is outside the active architecture. + +## Normative Language + +Normative terms define requirements, constraints, or authoritative meanings for Passpod. + +Informative terms provide explanation, context, examples, or non-binding guidance. + +## Active Terminology + +### Passpod + +Passpod is the overall architecture for transport-neutral trust negotiation using a standard, a handshake protocol, SDK implementations, specialized profiles, and pilot validation. + +### Passpod Standard + +The Passpod Standard defines the semantics of Passpod. + +It defines the meaning of the architecture and the relationship between the protocol, SDK, profiles, and pilot work. It does not define message formats, schemas, APIs, or implementation code. + +### Handshake Protocol + +The Handshake Protocol is the canonical transport-neutral negotiation flow: + +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` + +The protocol expresses the semantics of the Standard as an append-only negotiation between participants. + +### Handshake + +A handshake is a bounded negotiation history between participants. + +A handshake begins with a proposal, may include challenges and negotiation turns, records agreement when reached, and ends with closure. + +### Message + +A message is an immutable unit of handshake communication once accepted into handshake history. + +Messages derive their meaning from their position in the handshake and their relationship to prior context. + +### Participant + +A participant is a party that takes part in a handshake. + +Participants may be people, organizations, systems, agents, services, or profile-defined roles. The core architecture does not require a specific identity system. + +### Profile + +A profile specializes the Handshake Protocol for a domain, workflow, ecosystem, or trust context. + +Profiles may define domain expectations and extension rules, but they must preserve the core meaning of `PROPOSE`, `CHALLENGE`, `AGREE`, and `CLOSE`. + +### SDK + +The SDK implements the Handshake Protocol. + +An SDK may provide developer-facing tools for creating, interpreting, transmitting, storing, or inspecting protocol messages. SDKs must preserve Standard semantics and protocol ordering. + +### Evidence + +Evidence is information introduced into a handshake to support, question, qualify, or resolve negotiation. + +Profiles may define evidence expectations. The core terminology does not require a specific evidence format or storage system. + +### Reference + +A reference is a relationship from one part of a handshake to another piece of handshake context. + +References support lineage, reviewability, and negotiation continuity. This terminology does not define representation details. + +### Proposal + +A proposal is the negotiation meaning introduced by `PROPOSE`. + +It states what a participant wants to establish within the handshake. + +### Challenge + +A challenge is the negotiation meaning introduced by `CHALLENGE`. + +It asks for clarification, evidence, constraint, revision, qualification, or other work before agreement. + +### Agreement + +An agreement is the negotiation meaning introduced by `AGREE`. + +It records acceptance of the negotiated meaning within the scope of the handshake and any applicable profile. + +### Closure + +A closure is the negotiation meaning introduced by `CLOSE`. + +It ends active negotiation and records the terminal outcome of the handshake. + +### Extension + +An extension is a compatible specialization that adds domain detail, transport binding, implementation capability, or profile-level convention without redefining the core architecture. + +Extensions must preserve the Standard and the Handshake Protocol. + +### Conformance + +Conformance is alignment with the Passpod Standard, the Handshake Protocol, and any declared profile. + +Conformance is semantic before it is technical. A conformant implementation preserves core meaning even when transport, storage, or runtime choices differ. + +### Normative + +Normative material defines required meaning, constraints, or architecture. + +Normative material is authoritative for conformance. + +### Informative + +Informative material explains, illustrates, or contextualizes Passpod. + +Informative material is helpful but not authoritative for conformance unless a normative document explicitly adopts it. + +## Archived Legacy Terminology + +The following terms are archived legacy terminology. They may appear in historical, migration, or audit material, but they are outside the active Passpod architecture. + +### TASK Guard + +Archived legacy terminology outside the active architecture. + +### TASK Core + +Archived legacy terminology outside the active architecture. + +### Passpod Hub + +Archived legacy terminology outside the active architecture. + +### AgentTrust + +Archived legacy terminology outside the active architecture. + +### Control Packs + +Archived legacy terminology outside the active architecture. + +### Pilot Access Engine + +Archived legacy terminology outside the active architecture. + +### Sensitive Action Control + +Archived legacy terminology outside the active architecture. + +### Trust Action Receipt as the primary protocol object + +Archived legacy terminology outside the active architecture. + +Trust Action Receipts may remain relevant in historical or migration documentation, but they are not the primary protocol object in the active architecture. + +### Kill-State + +Archived legacy terminology outside the active architecture. + diff --git a/examples/invalid/close-before-agree.json b/examples/invalid/close-before-agree.json new file mode 100644 index 0000000..12b3863 --- /dev/null +++ b/examples/invalid/close-before-agree.json @@ -0,0 +1,47 @@ +{ + "handshakeIdentity": "hs-invalid-close-before-agree-001", + "lifecycle": "closed", + "terminalClosure": { + "isClosed": true, + "outcome": "completed", + "closeMessageReference": "msg-close-001" + }, + "messages": [ + { + "messageIdentity": "msg-propose-001", + "handshakeIdentity": "hs-invalid-close-before-agree-001", + "messageType": "PROPOSE", + "sender": "participant-alpha" + }, + { + "messageIdentity": "msg-challenge-001", + "handshakeIdentity": "hs-invalid-close-before-agree-001", + "parentReference": "msg-propose-001", + "messageType": "CHALLENGE", + "sender": "participant-beta" + }, + { + "messageIdentity": "msg-close-001", + "handshakeIdentity": "hs-invalid-close-before-agree-001", + "parentReference": "msg-challenge-001", + "messageType": "CLOSE", + "sender": "participant-alpha", + "extensions": { + "invalidExampleReason": "CLOSE claims completed closure before any AGREE message exists." + } + } + ], + "parentRelationships": [ + { + "messageReference": "msg-challenge-001", + "parentReference": "msg-propose-001", + "relationshipMeaning": "responds-to" + }, + { + "messageReference": "msg-close-001", + "parentReference": "msg-challenge-001", + "relationshipMeaning": "closes-without-agreement" + } + ] +} + diff --git a/examples/invalid/duplicate-message-id.json b/examples/invalid/duplicate-message-id.json new file mode 100644 index 0000000..b1ad9f2 --- /dev/null +++ b/examples/invalid/duplicate-message-id.json @@ -0,0 +1,30 @@ +{ + "handshakeIdentity": "hs-invalid-duplicate-message-id-001", + "lifecycle": "challenged", + "messages": [ + { + "messageIdentity": "msg-duplicate-001", + "handshakeIdentity": "hs-invalid-duplicate-message-id-001", + "messageType": "PROPOSE", + "sender": "participant-alpha" + }, + { + "messageIdentity": "msg-duplicate-001", + "handshakeIdentity": "hs-invalid-duplicate-message-id-001", + "parentReference": "msg-duplicate-001", + "messageType": "CHALLENGE", + "sender": "participant-beta", + "extensions": { + "invalidExampleReason": "Two accepted messages use the same message identity." + } + } + ], + "parentRelationships": [ + { + "messageReference": "msg-duplicate-001", + "parentReference": "msg-duplicate-001", + "relationshipMeaning": "ambiguous-self-reference" + } + ] +} + diff --git a/examples/invalid/invalid-transition.json b/examples/invalid/invalid-transition.json new file mode 100644 index 0000000..0543688 --- /dev/null +++ b/examples/invalid/invalid-transition.json @@ -0,0 +1,30 @@ +{ + "handshakeIdentity": "hs-invalid-transition-001", + "lifecycle": "agreed", + "messages": [ + { + "messageIdentity": "msg-propose-001", + "handshakeIdentity": "hs-invalid-transition-001", + "messageType": "PROPOSE", + "sender": "participant-alpha" + }, + { + "messageIdentity": "msg-agree-001", + "handshakeIdentity": "hs-invalid-transition-001", + "parentReference": "msg-propose-001", + "messageType": "AGREE", + "sender": "participant-beta", + "extensions": { + "invalidExampleReason": "AGREE appears before any CHALLENGE in the canonical negotiation flow." + } + } + ], + "parentRelationships": [ + { + "messageReference": "msg-agree-001", + "parentReference": "msg-propose-001", + "relationshipMeaning": "skips-challenge" + } + ] +} + diff --git a/examples/invalid/missing-parent.json b/examples/invalid/missing-parent.json new file mode 100644 index 0000000..83b522c --- /dev/null +++ b/examples/invalid/missing-parent.json @@ -0,0 +1,22 @@ +{ + "handshakeIdentity": "hs-invalid-missing-parent-001", + "lifecycle": "challenged", + "messages": [ + { + "messageIdentity": "msg-propose-001", + "handshakeIdentity": "hs-invalid-missing-parent-001", + "messageType": "PROPOSE", + "sender": "participant-alpha" + }, + { + "messageIdentity": "msg-challenge-001", + "handshakeIdentity": "hs-invalid-missing-parent-001", + "messageType": "CHALLENGE", + "sender": "participant-beta", + "extensions": { + "invalidExampleReason": "CHALLENGE is missing a parent reference to earlier handshake context." + } + } + ] +} + diff --git a/examples/invalid/redefine-message-type.json b/examples/invalid/redefine-message-type.json new file mode 100644 index 0000000..65cb38a --- /dev/null +++ b/examples/invalid/redefine-message-type.json @@ -0,0 +1,23 @@ +{ + "profileIdentity": "profile-invalid-redefine-message-type-001", + "profileVersion": "0.1", + "lifecycle": "draft", + "metadata": { + "name": "Invalid Message Type Redefinition", + "description": "A profile model fixture that attempts to redefine canonical message semantics." + }, + "mayDefine": { + "terminology": { + "PROPOSE": "This invalid profile attempts to make PROPOSE close a handshake." + }, + "domainSpecificExtensions": { + "messageTypeRedefinitions": { + "PROPOSE": "close" + } + } + }, + "extensions": { + "invalidExampleReason": "Profiles may extend usage but must not redefine PROPOSE, CHALLENGE, AGREE, or CLOSE." + } +} + diff --git a/examples/valid/complete-handshake.json b/examples/valid/complete-handshake.json new file mode 100644 index 0000000..43b0d16 --- /dev/null +++ b/examples/valid/complete-handshake.json @@ -0,0 +1,66 @@ +{ + "handshakeIdentity": "hs-complete-001", + "lifecycle": "closed", + "terminalClosure": { + "isClosed": true, + "outcome": "completed", + "closeMessageReference": "msg-close-001" + }, + "messages": [ + { + "messageIdentity": "msg-propose-001", + "handshakeIdentity": "hs-complete-001", + "messageType": "PROPOSE", + "sender": "participant-alpha", + "recipient": "participant-beta" + }, + { + "messageIdentity": "msg-challenge-001", + "handshakeIdentity": "hs-complete-001", + "parentReference": "msg-propose-001", + "messageType": "CHALLENGE", + "sender": "participant-beta", + "recipient": "participant-alpha", + "evidenceReferences": [ + "evidence-request-001" + ] + }, + { + "messageIdentity": "msg-agree-001", + "handshakeIdentity": "hs-complete-001", + "parentReference": "msg-challenge-001", + "messageType": "AGREE", + "sender": "participant-alpha", + "recipient": "participant-beta", + "evidenceReferences": [ + "evidence-response-001" + ] + }, + { + "messageIdentity": "msg-close-001", + "handshakeIdentity": "hs-complete-001", + "parentReference": "msg-agree-001", + "messageType": "CLOSE", + "sender": "participant-beta", + "recipient": "participant-alpha" + } + ], + "parentRelationships": [ + { + "messageReference": "msg-challenge-001", + "parentReference": "msg-propose-001", + "relationshipMeaning": "responds-to" + }, + { + "messageReference": "msg-agree-001", + "parentReference": "msg-challenge-001", + "relationshipMeaning": "resolves" + }, + { + "messageReference": "msg-close-001", + "parentReference": "msg-agree-001", + "relationshipMeaning": "closes" + } + ] +} + diff --git a/examples/valid/minimal-profile.json b/examples/valid/minimal-profile.json new file mode 100644 index 0000000..2f0cf86 --- /dev/null +++ b/examples/valid/minimal-profile.json @@ -0,0 +1,10 @@ +{ + "profileIdentity": "profile-minimal-001", + "profileVersion": "0.1", + "lifecycle": "draft", + "metadata": { + "name": "Minimal Profile Model Example", + "description": "A minimal profile model fixture that does not prescribe an active profile domain." + } +} + diff --git a/examples/valid/minimal-propose.json b/examples/valid/minimal-propose.json new file mode 100644 index 0000000..bee8a2f --- /dev/null +++ b/examples/valid/minimal-propose.json @@ -0,0 +1,7 @@ +{ + "messageIdentity": "msg-propose-001", + "handshakeIdentity": "hs-minimal-propose-001", + "messageType": "PROPOSE", + "sender": "participant-alpha" +} + diff --git a/examples/valid/propose-challenge-agree.json b/examples/valid/propose-challenge-agree.json new file mode 100644 index 0000000..af29384 --- /dev/null +++ b/examples/valid/propose-challenge-agree.json @@ -0,0 +1,48 @@ +{ + "handshakeIdentity": "hs-propose-challenge-agree-001", + "lifecycle": "agreed", + "messages": [ + { + "messageIdentity": "msg-propose-001", + "handshakeIdentity": "hs-propose-challenge-agree-001", + "messageType": "PROPOSE", + "sender": "participant-alpha", + "recipient": "participant-beta" + }, + { + "messageIdentity": "msg-challenge-001", + "handshakeIdentity": "hs-propose-challenge-agree-001", + "parentReference": "msg-propose-001", + "messageType": "CHALLENGE", + "sender": "participant-beta", + "recipient": "participant-alpha", + "evidenceReferences": [ + "evidence-request-001" + ] + }, + { + "messageIdentity": "msg-agree-001", + "handshakeIdentity": "hs-propose-challenge-agree-001", + "parentReference": "msg-challenge-001", + "messageType": "AGREE", + "sender": "participant-alpha", + "recipient": "participant-beta", + "evidenceReferences": [ + "evidence-response-001" + ] + } + ], + "parentRelationships": [ + { + "messageReference": "msg-challenge-001", + "parentReference": "msg-propose-001", + "relationshipMeaning": "responds-to" + }, + { + "messageReference": "msg-agree-001", + "parentReference": "msg-challenge-001", + "relationshipMeaning": "resolves" + } + ] +} + diff --git a/examples/valid/propose-challenge.json b/examples/valid/propose-challenge.json new file mode 100644 index 0000000..5146275 --- /dev/null +++ b/examples/valid/propose-challenge.json @@ -0,0 +1,32 @@ +{ + "handshakeIdentity": "hs-propose-challenge-001", + "lifecycle": "challenged", + "messages": [ + { + "messageIdentity": "msg-propose-001", + "handshakeIdentity": "hs-propose-challenge-001", + "messageType": "PROPOSE", + "sender": "participant-alpha", + "recipient": "participant-beta" + }, + { + "messageIdentity": "msg-challenge-001", + "handshakeIdentity": "hs-propose-challenge-001", + "parentReference": "msg-propose-001", + "messageType": "CHALLENGE", + "sender": "participant-beta", + "recipient": "participant-alpha", + "evidenceReferences": [ + "evidence-request-001" + ] + } + ], + "parentRelationships": [ + { + "messageReference": "msg-challenge-001", + "parentReference": "msg-propose-001", + "relationshipMeaning": "responds-to" + } + ] +} + diff --git a/passpod/__init__.py b/passpod/__init__.py new file mode 100644 index 0000000..5c855c9 --- /dev/null +++ b/passpod/__init__.py @@ -0,0 +1,12 @@ +from .errors import PasspodValidationError +from .handshake import Handshake +from .message import Message +from .profile import Profile + +__all__ = [ + "Handshake", + "Message", + "PasspodValidationError", + "Profile", +] + diff --git a/passpod/errors.py b/passpod/errors.py new file mode 100644 index 0000000..2b1d116 --- /dev/null +++ b/passpod/errors.py @@ -0,0 +1,21 @@ +class PasspodValidationError(ValueError): + """SDK-facing validation failure with deterministic validator errors.""" + + def __init__(self, operation, errors): + self.operation = operation + self.errors = tuple(_copy_error(error) for error in errors) + super().__init__(self._summary()) + + def _summary(self): + if not self.errors: + return f"{self.operation} failed validation" + + codes = ", ".join(error.get("code", "UNKNOWN") for error in self.errors) + return f"{self.operation} failed validation: {codes}" + + +def _copy_error(error): + if isinstance(error, dict): + return dict(error) + return {"code": "UNKNOWN", "path": "$", "message": str(error)} + diff --git a/passpod/handshake.py b/passpod/handshake.py new file mode 100644 index 0000000..ea9092e --- /dev/null +++ b/passpod/handshake.py @@ -0,0 +1,113 @@ +from copy import deepcopy +from dataclasses import dataclass + +from validator.semantic_validator import validateHandshake + +from .errors import PasspodValidationError +from .message import Message + + +MESSAGE_STATE = { + "PROPOSE": "proposed", + "CHALLENGE": "challenged", + "AGREE": "agreed", + "CLOSE": "closed", +} + + +@dataclass(frozen=True) +class Handshake: + _data: dict + + def __init__( + self, + handshakeIdentity=None, + messages=None, + lifecycle=None, + terminalClosure=None, + parentRelationships=None, + profileAssociation=None, + versionAssociation=None, + extensions=None, + ): + data = { + "handshakeIdentity": deepcopy(handshakeIdentity), + "messages": [_message_mapping(message) for message in (messages or [])], + } + + optional = { + "lifecycle": lifecycle, + "terminalClosure": terminalClosure, + "parentRelationships": parentRelationships, + "profileAssociation": profileAssociation, + "versionAssociation": versionAssociation, + "extensions": extensions, + } + + for key, value in optional.items(): + if value is not None: + data[key] = deepcopy(value) + + object.__setattr__(self, "_data", data) + if self._data.get("messages"): + self.validate() + + @classmethod + def from_mapping(cls, mapping): + instance = cls.__new__(cls) + object.__setattr__(instance, "_data", deepcopy(dict(mapping))) + if instance._data.get("messages"): + instance.validate() + return instance + + @property + def handshake_identity(self): + return deepcopy(self._data.get("handshakeIdentity")) + + @property + def history(self): + return tuple(Message.from_mapping(message) for message in self._data.get("messages", [])) + + @property + def lifecycle(self): + explicit = self._data.get("lifecycle") + if explicit is not None: + return explicit + + messages = self._data.get("messages", []) + if not messages: + return "not_started" + + return MESSAGE_STATE.get(messages[-1].get("messageType"), "not_started") + + @property + def is_closed(self): + if self.lifecycle == "closed": + return True + + messages = self._data.get("messages", []) + return bool(messages and messages[-1].get("messageType") == "CLOSE") + + def append(self, message): + candidate = self.to_mapping() + candidate.setdefault("messages", []) + candidate["messages"].append(_message_mapping(message)) + return self.from_mapping(candidate) + + def to_mapping(self): + return deepcopy(self._data) + + def validate(self): + if not self._data.get("messages"): + return {"valid": True, "errors": []} + + result = validateHandshake(self.to_mapping()) + if not result.get("valid"): + raise PasspodValidationError("validateHandshake", result.get("errors", [])) + return result + + +def _message_mapping(message): + if isinstance(message, Message): + return message.to_mapping() + return deepcopy(dict(message)) diff --git a/passpod/message.py b/passpod/message.py new file mode 100644 index 0000000..9f525c7 --- /dev/null +++ b/passpod/message.py @@ -0,0 +1,90 @@ +from copy import deepcopy +from dataclasses import dataclass + +from validator.semantic_validator import validateMessage + +from .errors import PasspodValidationError + + +@dataclass(frozen=True) +class Message: + _data: dict + + def __init__( + self, + messageIdentity=None, + handshakeIdentity=None, + messageType=None, + sender=None, + parentReference=None, + recipient=None, + timestamp=None, + profileAssociation=None, + versionAssociation=None, + evidenceReferences=None, + extensions=None, + ): + data = { + "messageIdentity": deepcopy(messageIdentity), + "handshakeIdentity": deepcopy(handshakeIdentity), + "messageType": deepcopy(messageType), + "sender": deepcopy(sender), + } + + optional = { + "parentReference": parentReference, + "recipient": recipient, + "timestamp": timestamp, + "profileAssociation": profileAssociation, + "versionAssociation": versionAssociation, + "evidenceReferences": evidenceReferences, + "extensions": extensions, + } + + for key, value in optional.items(): + if value is not None: + data[key] = deepcopy(value) + + object.__setattr__(self, "_data", data) + self.validate() + + @classmethod + def from_mapping(cls, mapping): + instance = cls.__new__(cls) + object.__setattr__(instance, "_data", deepcopy(dict(mapping))) + instance.validate() + return instance + + @property + def message_identity(self): + return deepcopy(self._data.get("messageIdentity")) + + @property + def handshake_identity(self): + return deepcopy(self._data.get("handshakeIdentity")) + + @property + def message_type(self): + return deepcopy(self._data.get("messageType")) + + @property + def parent_reference(self): + return deepcopy(self._data.get("parentReference")) + + @property + def sender(self): + return deepcopy(self._data.get("sender")) + + @property + def recipient(self): + return deepcopy(self._data.get("recipient")) + + def to_mapping(self): + return deepcopy(self._data) + + def validate(self): + result = validateMessage(self.to_mapping()) + if not result.get("valid"): + raise PasspodValidationError("validateMessage", result.get("errors", [])) + return result + diff --git a/passpod/profile.py b/passpod/profile.py new file mode 100644 index 0000000..d4d1df2 --- /dev/null +++ b/passpod/profile.py @@ -0,0 +1,70 @@ +from copy import deepcopy +from dataclasses import dataclass + +from validator.semantic_validator import validateProfile + +from .errors import PasspodValidationError + + +@dataclass(frozen=True) +class Profile: + _data: dict + + def __init__( + self, + profileIdentity=None, + profileVersion=None, + lifecycle=None, + metadata=None, + mayDefine=None, + mustNotRedefine=None, + extensions=None, + ): + data = { + "profileIdentity": deepcopy(profileIdentity), + "profileVersion": deepcopy(profileVersion), + "lifecycle": deepcopy(lifecycle), + } + + optional = { + "metadata": metadata, + "mayDefine": mayDefine, + "mustNotRedefine": mustNotRedefine, + "extensions": extensions, + } + + for key, value in optional.items(): + if value is not None: + data[key] = deepcopy(value) + + object.__setattr__(self, "_data", data) + self.validate() + + @classmethod + def from_mapping(cls, mapping): + instance = cls.__new__(cls) + object.__setattr__(instance, "_data", deepcopy(dict(mapping))) + instance.validate() + return instance + + @property + def profile_identity(self): + return deepcopy(self._data.get("profileIdentity")) + + @property + def profile_version(self): + return deepcopy(self._data.get("profileVersion")) + + @property + def lifecycle(self): + return deepcopy(self._data.get("lifecycle")) + + def to_mapping(self): + return deepcopy(self._data) + + def validate(self): + result = validateProfile(self.to_mapping()) + if not result.get("valid"): + raise PasspodValidationError("validateProfile", result.get("errors", [])) + return result + diff --git a/schemas/handshake.schema.json b/schemas/handshake.schema.json new file mode 100644 index 0000000..d330fc9 --- /dev/null +++ b/schemas/handshake.schema.json @@ -0,0 +1,168 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Passpod Handshake Schema", + "description": "Machine-readable representation of the conceptual Passpod handshake model. The schema represents the canonical flow without embedding implementation transition logic.", + "type": "object", + "required": [ + "handshakeIdentity", + "messages" + ], + "properties": { + "handshakeIdentity": { + "$ref": "#/$defs/conceptualIdentifier", + "description": "Stable conceptual identifier that lets participants recognize which messages belong to the same negotiation." + }, + "lifecycle": { + "$ref": "#/$defs/handshakeLifecycle", + "description": "Conceptual lifecycle state of the handshake." + }, + "terminalClosure": { + "$ref": "#/$defs/terminalClosure", + "description": "Closure concept for terminal handshake outcome. Closure is terminal, but this schema does not implement transition logic." + }, + "messages": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "message.schema.json" + }, + "description": "Ordered append-only message history. Ordering is represented by array order; append-only behavior is a semantic requirement outside this schema." + }, + "parentRelationships": { + "type": "array", + "items": { + "$ref": "#/$defs/parentRelationship" + }, + "description": "Conceptual parent relationships among messages in the handshake." + }, + "profileAssociation": { + "$ref": "#/$defs/conceptualReference", + "description": "Optional profile context associated with the handshake." + }, + "versionAssociation": { + "$ref": "#/$defs/conceptualValue", + "description": "Optional version context. The frozen specification does not prescribe version syntax." + }, + "extensions": { + "type": "object", + "description": "Compatible extension points. Extensions must not redefine core semantics.", + "additionalProperties": { + "$ref": "#/$defs/extensionValue" + } + } + }, + "additionalProperties": false, + "$defs": { + "conceptualIdentifier": { + "description": "Identifier concept. The frozen specification does not prescribe identifier syntax.", + "oneOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "object", + "minProperties": 1, + "additionalProperties": true + } + ] + }, + "conceptualReference": { + "description": "Reference concept. The frozen specification does not prescribe representation details.", + "oneOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "object", + "minProperties": 1, + "additionalProperties": true + } + ] + }, + "conceptualValue": { + "description": "Conceptual value with intentionally unspecified representation.", + "type": [ + "string", + "number", + "boolean", + "object", + "array", + "null" + ] + }, + "handshakeLifecycle": { + "type": "string", + "enum": [ + "not_started", + "proposed", + "challenged", + "agreed", + "closed" + ], + "description": "Conceptual lifecycle state from the State Model." + }, + "terminalClosure": { + "type": "object", + "required": [ + "isClosed" + ], + "properties": { + "isClosed": { + "type": "boolean", + "description": "Whether the handshake has reached closure." + }, + "outcome": { + "type": "string", + "enum": [ + "completed", + "unresolved", + "withdrawn", + "declined" + ], + "description": "Conceptual terminal outcome named in the State Model. Profiles may define more specific terminal meanings." + }, + "closeMessageReference": { + "$ref": "#/$defs/conceptualReference", + "description": "Reference to the CLOSE message or closure context." + } + }, + "additionalProperties": false + }, + "parentRelationship": { + "type": "object", + "required": [ + "messageReference", + "parentReference" + ], + "properties": { + "messageReference": { + "$ref": "#/$defs/conceptualReference", + "description": "Reference to the message that has a parent." + }, + "parentReference": { + "$ref": "#/$defs/conceptualReference", + "description": "Reference to earlier handshake context." + }, + "relationshipMeaning": { + "type": "string", + "description": "Optional conceptual meaning of the relationship. The frozen specification does not prescribe controlled values." + } + }, + "additionalProperties": false + }, + "extensionValue": { + "description": "Extension value. Extensions must not redefine core semantics.", + "type": [ + "object", + "array", + "string", + "number", + "integer", + "boolean", + "null" + ] + } + } +} diff --git a/schemas/message.schema.json b/schemas/message.schema.json new file mode 100644 index 0000000..fad72d4 --- /dev/null +++ b/schemas/message.schema.json @@ -0,0 +1,182 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Passpod Message Schema", + "description": "Machine-readable representation of the conceptual Passpod message model. Representation details remain intentionally broad because the frozen specification keeps encoding, transport, storage, signatures, cryptography, and implementation unspecified.", + "type": "object", + "required": [ + "messageIdentity", + "handshakeIdentity", + "messageType", + "sender" + ], + "properties": { + "messageIdentity": { + "$ref": "#/$defs/conceptualIdentifier", + "description": "Conceptual ability to distinguish one message from another." + }, + "handshakeIdentity": { + "$ref": "#/$defs/conceptualIdentifier", + "description": "Conceptual ability to associate this message with a bounded handshake history." + }, + "parentReference": { + "$ref": "#/$defs/conceptualReference", + "description": "Reference to earlier handshake context. The representation is intentionally unspecified." + }, + "sender": { + "$ref": "#/$defs/participantReference", + "description": "Participant responsible for emitting the message." + }, + "recipient": { + "oneOf": [ + { + "$ref": "#/$defs/participantReference" + }, + { + "type": "array", + "items": { + "$ref": "#/$defs/participantReference" + } + } + ], + "description": "Participant, participants, role, or audience addressed by the message." + }, + "timestamp": { + "$ref": "#/$defs/conceptualValue", + "description": "Timestamp concept for ordering, reviewability, and interpretation. Format, precision, authority, and clock source are intentionally unspecified." + }, + "messageType": { + "type": "string", + "enum": [ + "PROPOSE", + "CHALLENGE", + "AGREE", + "CLOSE" + ], + "description": "Canonical protocol role played by the message." + }, + "profileAssociation": { + "$ref": "#/$defs/profileAssociation", + "description": "Profile context that specializes the message or handshake." + }, + "versionAssociation": { + "$ref": "#/$defs/versionAssociation", + "description": "Relevant version context for the Standard, protocol, message model, profile, or extension." + }, + "evidenceReferences": { + "type": "array", + "items": { + "$ref": "#/$defs/conceptualReference" + }, + "description": "References to evidence used to support, question, qualify, or resolve negotiation." + }, + "extensions": { + "type": "object", + "description": "Compatible extension points. Extensions must preserve the Standard, Handshake Protocol, and append-only message history.", + "additionalProperties": { + "$ref": "#/$defs/extensionValue" + } + } + }, + "additionalProperties": false, + "$defs": { + "conceptualIdentifier": { + "description": "Identifier concept. The frozen specification does not prescribe identifier syntax.", + "oneOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "object", + "minProperties": 1, + "additionalProperties": true + } + ] + }, + "conceptualReference": { + "description": "Reference concept. The frozen specification does not prescribe representation details.", + "oneOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "object", + "minProperties": 1, + "additionalProperties": true + } + ] + }, + "conceptualValue": { + "description": "Conceptual value with intentionally unspecified representation.", + "type": [ + "string", + "number", + "boolean", + "object", + "array", + "null" + ] + }, + "participantReference": { + "description": "Participant concept. The core architecture does not require a specific identity system.", + "oneOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "object", + "minProperties": 1, + "additionalProperties": true + } + ] + }, + "profileAssociation": { + "description": "Profile association concept. The frozen specification does not prescribe encoding.", + "anyOf": [ + { + "$ref": "#/$defs/conceptualIdentifier" + }, + { + "type": "object", + "properties": { + "profileIdentity": { + "$ref": "#/$defs/conceptualIdentifier" + }, + "profileVersion": { + "$ref": "#/$defs/conceptualValue" + } + }, + "additionalProperties": true + } + ] + }, + "versionAssociation": { + "description": "Version association concept. The frozen specification does not prescribe version syntax.", + "anyOf": [ + { + "$ref": "#/$defs/conceptualValue" + }, + { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/conceptualValue" + } + } + ] + }, + "extensionValue": { + "description": "Extension value. Extensions must not redefine core semantics.", + "type": [ + "object", + "array", + "string", + "number", + "integer", + "boolean", + "null" + ] + } + } +} diff --git a/schemas/profile.schema.json b/schemas/profile.schema.json new file mode 100644 index 0000000..5dd45b4 --- /dev/null +++ b/schemas/profile.schema.json @@ -0,0 +1,169 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Passpod Profile Schema", + "description": "Machine-readable representation of the conceptual Passpod Profile model. This schema represents the Profile model only; it does not define actual profiles.", + "type": "object", + "required": [ + "profileIdentity", + "profileVersion", + "lifecycle" + ], + "properties": { + "profileIdentity": { + "$ref": "#/$defs/conceptualIdentifier", + "description": "Conceptual identity of the profile." + }, + "profileVersion": { + "$ref": "#/$defs/conceptualValue", + "description": "Profile version concept. Version syntax is intentionally unspecified." + }, + "lifecycle": { + "$ref": "#/$defs/profileLifecycle", + "description": "Conceptual governance lifecycle stage, not an implementation state." + }, + "metadata": { + "$ref": "#/$defs/profileMetadata", + "description": "Profile metadata that does not create an actual profile domain by itself." + }, + "mayDefine": { + "type": "object", + "description": "Conceptual areas a profile may define while preserving the Standard and Protocol.", + "properties": { + "participantRoles": { + "$ref": "#/$defs/conceptualValue" + }, + "evidenceExpectations": { + "$ref": "#/$defs/conceptualValue" + }, + "terminology": { + "$ref": "#/$defs/conceptualValue" + }, + "domainSpecificExtensions": { + "$ref": "#/$defs/conceptualValue" + }, + "versionExpectations": { + "$ref": "#/$defs/conceptualValue" + }, + "workflowGuidance": { + "$ref": "#/$defs/conceptualValue" + }, + "terminalOutcomeInterpretation": { + "$ref": "#/$defs/conceptualValue" + }, + "optionalConstraints": { + "$ref": "#/$defs/conceptualValue" + } + }, + "additionalProperties": false + }, + "mustNotRedefine": { + "type": "array", + "readOnly": true, + "items": { + "type": "string", + "enum": [ + "PROPOSE", + "CHALLENGE", + "AGREE", + "CLOSE", + "append-only history", + "immutable accepted messages", + "Standard semantics", + "Protocol semantics" + ] + }, + "uniqueItems": true, + "description": "Core semantics that profiles must not redefine." + }, + "extensions": { + "type": "object", + "description": "Compatible profile extensions. Extensions must preserve semantic compatibility.", + "additionalProperties": { + "$ref": "#/$defs/extensionValue" + } + } + }, + "additionalProperties": false, + "$defs": { + "conceptualIdentifier": { + "description": "Identifier concept. The frozen specification does not prescribe identifier syntax.", + "oneOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "object", + "minProperties": 1, + "additionalProperties": true + } + ] + }, + "conceptualValue": { + "description": "Conceptual value with intentionally unspecified representation.", + "type": [ + "string", + "number", + "boolean", + "object", + "array", + "null" + ] + }, + "profileLifecycle": { + "type": "string", + "enum": [ + "draft", + "review", + "approved", + "deprecated", + "archived" + ], + "description": "Conceptual profile lifecycle stage." + }, + "profileMetadata": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Profile name metadata." + }, + "description": { + "type": "string", + "description": "Profile description metadata." + }, + "domain": { + "type": "string", + "description": "Domain metadata. This does not prescribe any active profile." + }, + "normativeReferences": { + "type": "array", + "items": { + "type": "string" + }, + "description": "References to normative Passpod documents or profile materials." + }, + "informativeReferences": { + "type": "array", + "items": { + "type": "string" + }, + "description": "References to informative materials." + } + }, + "additionalProperties": false + }, + "extensionValue": { + "description": "Extension value. Extensions must preserve semantic compatibility.", + "type": [ + "object", + "array", + "string", + "number", + "integer", + "boolean", + "null" + ] + } + } +} diff --git a/tests/test_sdk_core.py b/tests/test_sdk_core.py new file mode 100644 index 0000000..35e604a --- /dev/null +++ b/tests/test_sdk_core.py @@ -0,0 +1,254 @@ +import unittest +from dataclasses import FrozenInstanceError + +from passpod import Handshake, Message, PasspodValidationError, Profile + + +def error_codes(error): + return [entry["code"] for entry in error.errors] + + +class MessageTests(unittest.TestCase): + def test_valid_message_construction(self): + message = Message( + messageIdentity="msg-1", + handshakeIdentity="hs-1", + messageType="PROPOSE", + sender="participant-alpha", + ) + + self.assertEqual("msg-1", message.message_identity) + self.assertEqual("hs-1", message.handshake_identity) + self.assertEqual("PROPOSE", message.message_type) + + def test_construction_from_mapping(self): + message = Message.from_mapping( + { + "messageIdentity": "msg-1", + "handshakeIdentity": "hs-1", + "messageType": "PROPOSE", + "sender": "participant-alpha", + } + ) + + self.assertEqual("participant-alpha", message.sender) + + def test_mapping_round_trip(self): + data = { + "messageIdentity": "msg-1", + "handshakeIdentity": "hs-1", + "messageType": "PROPOSE", + "sender": "participant-alpha", + "recipient": "participant-beta", + "evidenceReferences": ["ev-1"], + } + message = Message.from_mapping(data) + + self.assertEqual(data, message.to_mapping()) + + def test_validation_failure(self): + with self.assertRaises(PasspodValidationError) as raised: + Message.from_mapping( + { + "messageIdentity": "msg-1", + "handshakeIdentity": "hs-1", + "messageType": "UNKNOWN", + "sender": "participant-alpha", + } + ) + + self.assertIn("SCHEMA_INVALID", error_codes(raised.exception)) + + def test_attempted_direct_mutation(self): + message = Message("msg-1", "hs-1", "PROPOSE", "participant-alpha") + + with self.assertRaises(FrozenInstanceError): + message._data = {} + + def test_external_mapping_mutation_does_not_alter_state(self): + data = { + "messageIdentity": "msg-1", + "handshakeIdentity": "hs-1", + "messageType": "PROPOSE", + "sender": {"id": "participant-alpha"}, + "evidenceReferences": ["ev-1"], + } + message = Message.from_mapping(data) + + data["sender"]["id"] = "changed" + data["evidenceReferences"].append("ev-2") + exported = message.to_mapping() + exported["sender"]["id"] = "changed-again" + + self.assertEqual({"id": "participant-alpha"}, message.sender) + self.assertEqual(["ev-1"], message.to_mapping()["evidenceReferences"]) + + +class HandshakeTests(unittest.TestCase): + def msg(self, identity, message_type, parent=None, handshake_identity="hs-1"): + data = { + "messageIdentity": identity, + "handshakeIdentity": handshake_identity, + "messageType": message_type, + "sender": "participant-alpha", + } + if parent is not None: + data["parentReference"] = parent + return Message.from_mapping(data) + + def test_creation_with_handshake_identity(self): + handshake = Handshake("hs-1") + + self.assertEqual("hs-1", handshake.handshake_identity) + self.assertEqual("not_started", handshake.lifecycle) + self.assertFalse(handshake.is_closed) + self.assertEqual(0, len(handshake.history)) + + def test_creation_from_minimal_valid_propose(self): + handshake = Handshake("hs-1", messages=[self.msg("msg-1", "PROPOSE")]) + + self.assertEqual("hs-1", handshake.handshake_identity) + self.assertEqual("proposed", handshake.lifecycle) + self.assertFalse(handshake.is_closed) + self.assertEqual(1, len(handshake.history)) + + def test_append_challenge_agree_close_and_states(self): + proposed = Handshake("hs-1", messages=[self.msg("msg-1", "PROPOSE")]) + challenged = proposed.append(self.msg("msg-2", "CHALLENGE", parent="msg-1")) + agreed = challenged.append(self.msg("msg-3", "AGREE", parent="msg-2")) + closed = agreed.append(self.msg("msg-4", "CLOSE", parent="msg-3")) + + self.assertEqual("proposed", proposed.lifecycle) + self.assertEqual("challenged", challenged.lifecycle) + self.assertEqual("agreed", agreed.lifecycle) + self.assertEqual("closed", closed.lifecycle) + self.assertTrue(closed.is_closed) + + def test_append_returns_new_handshake_and_preserves_prior_history(self): + proposed = Handshake("hs-1", messages=[self.msg("msg-1", "PROPOSE")]) + challenged = proposed.append(self.msg("msg-2", "CHALLENGE", parent="msg-1")) + + self.assertIsNot(proposed, challenged) + self.assertEqual(1, len(proposed.history)) + self.assertEqual(2, len(challenged.history)) + + def test_invalid_transition_is_rejected(self): + proposed = Handshake("hs-1", messages=[self.msg("msg-1", "PROPOSE")]) + + with self.assertRaises(PasspodValidationError) as raised: + proposed.append(self.msg("msg-2", "AGREE", parent="msg-1")) + + self.assertIn("INVALID_TRANSITION", error_codes(raised.exception)) + self.assertEqual(1, len(proposed.history)) + + def test_missing_parent_is_rejected(self): + proposed = Handshake("hs-1", messages=[self.msg("msg-1", "PROPOSE")]) + + with self.assertRaises(PasspodValidationError) as raised: + proposed.append(self.msg("msg-2", "CHALLENGE")) + + self.assertIn("PARENT_REQUIRED", error_codes(raised.exception)) + + def test_duplicate_message_identity_is_rejected(self): + proposed = Handshake("hs-1", messages=[self.msg("msg-1", "PROPOSE")]) + + with self.assertRaises(PasspodValidationError) as raised: + proposed.append(self.msg("msg-1", "CHALLENGE", parent="msg-1")) + + self.assertIn("DUPLICATE_MESSAGE_ID", error_codes(raised.exception)) + + def test_mismatched_handshake_identity_is_rejected(self): + proposed = Handshake("hs-1", messages=[self.msg("msg-1", "PROPOSE")]) + + with self.assertRaises(PasspodValidationError) as raised: + proposed.append(self.msg("msg-2", "CHALLENGE", parent="msg-1", handshake_identity="other")) + + self.assertIn("HANDSHAKE_ID_MISMATCH", error_codes(raised.exception)) + + def test_message_after_close_is_rejected(self): + closed = ( + Handshake("hs-1", messages=[self.msg("msg-1", "PROPOSE")]) + .append(self.msg("msg-2", "CHALLENGE", parent="msg-1")) + .append(self.msg("msg-3", "AGREE", parent="msg-2")) + .append(self.msg("msg-4", "CLOSE", parent="msg-3")) + ) + + with self.assertRaises(PasspodValidationError) as raised: + closed.append(self.msg("msg-5", "CHALLENGE", parent="msg-4")) + + self.assertIn("MESSAGE_AFTER_CLOSE", error_codes(raised.exception)) + + def test_history_cannot_be_externally_reordered_or_modified(self): + handshake = Handshake("hs-1", messages=[self.msg("msg-1", "PROPOSE")]) + history = handshake.history + + with self.assertRaises(AttributeError): + history.append(self.msg("msg-2", "CHALLENGE", parent="msg-1")) + + exported = handshake.to_mapping() + exported["messages"].clear() + + self.assertEqual(1, len(handshake.history)) + self.assertEqual("msg-1", handshake.history[0].message_identity) + + +class ProfileTests(unittest.TestCase): + def test_valid_minimal_profile_construction(self): + profile = Profile("profile-1", "0.1", "draft") + + self.assertEqual("profile-1", profile.profile_identity) + self.assertEqual("0.1", profile.profile_version) + self.assertEqual("draft", profile.lifecycle) + + def test_mapping_round_trip(self): + data = { + "profileIdentity": "profile-1", + "profileVersion": "0.1", + "lifecycle": "draft", + "metadata": {"name": "Minimal"}, + } + profile = Profile.from_mapping(data) + + self.assertEqual(data, profile.to_mapping()) + + def test_core_semantic_redefinition_is_rejected(self): + with self.assertRaises(PasspodValidationError) as raised: + Profile.from_mapping( + { + "profileIdentity": "profile-invalid", + "profileVersion": "0.1", + "lifecycle": "draft", + "mayDefine": { + "terminology": { + "PROPOSE": "Invalid redefinition" + } + }, + } + ) + + self.assertIn("CORE_SEMANTIC_REDEFINITION", error_codes(raised.exception)) + + def test_attempted_direct_mutation(self): + profile = Profile("profile-1", "0.1", "draft") + + with self.assertRaises(FrozenInstanceError): + profile._data = {} + + +class ValidatorConsumptionTests(unittest.TestCase): + def test_message_validation_uses_existing_validator(self): + with self.assertRaises(PasspodValidationError) as raised: + Message.from_mapping( + { + "messageIdentity": "msg-1", + "handshakeIdentity": "hs-1", + "messageType": "PROPOSE", + } + ) + + self.assertEqual("validateMessage", raised.exception.operation) + self.assertIn("SCHEMA_INVALID", error_codes(raised.exception)) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_semantic_validator.py b/tests/test_semantic_validator.py new file mode 100644 index 0000000..06b4b39 --- /dev/null +++ b/tests/test_semantic_validator.py @@ -0,0 +1,221 @@ +import importlib.util +import json +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +MODULE_PATH = ROOT / "validator" / "semantic_validator.py" + +spec = importlib.util.spec_from_file_location("semantic_validator", MODULE_PATH) +semantic_validator = importlib.util.module_from_spec(spec) +spec.loader.exec_module(semantic_validator) + + +def load_json(path): + return json.loads((ROOT / path).read_text(encoding="utf-8")) + + +def validate_fixture(path): + data = load_json(path) + if "profileIdentity" in data: + return semantic_validator.validateProfile(data) + if "messages" in data: + return semantic_validator.validateHandshake(data) + return semantic_validator.validateMessage(data) + + +def error_codes(result): + return [error["code"] for error in result["errors"]] + + +class FixtureValidationTests(unittest.TestCase): + def test_valid_fixtures_pass(self): + for path in sorted((ROOT / "examples" / "valid").glob("*.json")): + with self.subTest(path=path.name): + result = validate_fixture(path.relative_to(ROOT)) + self.assertTrue(result["valid"], result["errors"]) + self.assertEqual([], result["errors"]) + + def test_invalid_fixtures_fail_with_expected_codes(self): + expected = { + "missing-parent.json": semantic_validator.PARENT_REQUIRED, + "invalid-transition.json": semantic_validator.INVALID_TRANSITION, + "close-before-agree.json": semantic_validator.CLOSE_BEFORE_AGREE, + "duplicate-message-id.json": semantic_validator.DUPLICATE_MESSAGE_ID, + "redefine-message-type.json": semantic_validator.CORE_SEMANTIC_REDEFINITION, + } + + for path in sorted((ROOT / "examples" / "invalid").glob("*.json")): + with self.subTest(path=path.name): + result = validate_fixture(path.relative_to(ROOT)) + self.assertFalse(result["valid"]) + self.assertIn(expected[path.name], error_codes(result)) + + +class DirectSemanticRuleTests(unittest.TestCase): + def handshake(self, messages, **extra): + data = { + "handshakeIdentity": "hs-direct-001", + "lifecycle": extra.pop("lifecycle", "challenged"), + "messages": messages, + } + data.update(extra) + return data + + def message(self, identity, message_type, parent=None, handshake_identity="hs-direct-001"): + data = { + "messageIdentity": identity, + "handshakeIdentity": handshake_identity, + "messageType": message_type, + "sender": "participant-alpha", + } + if parent is not None: + data["parentReference"] = parent + return data + + def assert_has_code(self, result, code): + self.assertFalse(result["valid"]) + self.assertIn(code, error_codes(result)) + + def test_duplicate_message_identity(self): + result = semantic_validator.validateHandshake( + self.handshake( + [ + self.message("msg-1", "PROPOSE"), + self.message("msg-1", "CHALLENGE", parent="msg-1"), + ] + ) + ) + self.assert_has_code(result, semantic_validator.DUPLICATE_MESSAGE_ID) + + def test_mismatched_handshake_identity(self): + result = semantic_validator.validateHandshake( + self.handshake( + [ + self.message("msg-1", "PROPOSE"), + self.message("msg-2", "CHALLENGE", parent="msg-1", handshake_identity="other"), + ] + ) + ) + self.assert_has_code(result, semantic_validator.HANDSHAKE_ID_MISMATCH) + + def test_missing_parent(self): + result = semantic_validator.validateHandshake( + self.handshake( + [ + self.message("msg-1", "PROPOSE"), + self.message("msg-2", "CHALLENGE"), + ] + ) + ) + self.assert_has_code(result, semantic_validator.PARENT_REQUIRED) + + def test_nonexistent_parent(self): + result = semantic_validator.validateHandshake( + self.handshake( + [ + self.message("msg-1", "PROPOSE"), + self.message("msg-2", "CHALLENGE", parent="missing"), + ] + ) + ) + self.assert_has_code(result, semantic_validator.PARENT_NOT_FOUND) + + def test_self_parent_reference(self): + result = semantic_validator.validateHandshake( + self.handshake( + [ + self.message("msg-1", "PROPOSE"), + self.message("msg-2", "CHALLENGE", parent="msg-2"), + ] + ) + ) + self.assert_has_code(result, semantic_validator.PARENT_SELF_REFERENCE) + + def test_forward_parent_reference(self): + result = semantic_validator.validateHandshake( + self.handshake( + [ + self.message("msg-1", "PROPOSE"), + self.message("msg-2", "CHALLENGE", parent="msg-3"), + self.message("msg-3", "CHALLENGE", parent="msg-2"), + ] + ) + ) + self.assert_has_code(result, semantic_validator.PARENT_NOT_EARLIER) + + def test_first_message_not_propose(self): + result = semantic_validator.validateHandshake( + self.handshake([self.message("msg-1", "CHALLENGE")]) + ) + self.assert_has_code(result, semantic_validator.INITIAL_MESSAGE_NOT_PROPOSE) + + def test_invalid_lifecycle_transition(self): + result = semantic_validator.validateHandshake( + self.handshake( + [ + self.message("msg-1", "PROPOSE"), + self.message("msg-2", "AGREE", parent="msg-1"), + ], + lifecycle="agreed", + ) + ) + self.assert_has_code(result, semantic_validator.INVALID_TRANSITION) + + def test_message_after_close(self): + result = semantic_validator.validateHandshake( + self.handshake( + [ + self.message("msg-1", "PROPOSE"), + self.message("msg-2", "CHALLENGE", parent="msg-1"), + self.message("msg-3", "AGREE", parent="msg-2"), + self.message("msg-4", "CLOSE", parent="msg-3"), + self.message("msg-5", "CHALLENGE", parent="msg-4"), + ], + lifecycle="closed", + terminalClosure={ + "isClosed": True, + "outcome": "completed", + "closeMessageReference": "msg-4", + }, + ) + ) + self.assert_has_code(result, semantic_validator.MESSAGE_AFTER_CLOSE) + + def test_close_before_agree(self): + result = semantic_validator.validateHandshake( + self.handshake( + [ + self.message("msg-1", "PROPOSE"), + self.message("msg-2", "CHALLENGE", parent="msg-1"), + self.message("msg-3", "CLOSE", parent="msg-2"), + ], + lifecycle="closed", + terminalClosure={ + "isClosed": True, + "outcome": "completed", + "closeMessageReference": "msg-3", + }, + ) + ) + self.assert_has_code(result, semantic_validator.CLOSE_BEFORE_AGREE) + + def test_profile_attempt_to_redefine_canonical_message_type(self): + profile = { + "profileIdentity": "profile-direct-invalid-001", + "profileVersion": "0.1", + "lifecycle": "draft", + "mayDefine": { + "terminology": { + "PROPOSE": "Invalid attempt to redefine PROPOSE." + } + }, + } + result = semantic_validator.validateProfile(profile) + self.assert_has_code(result, semantic_validator.CORE_SEMANTIC_REDEFINITION) + + +if __name__ == "__main__": + unittest.main() + diff --git a/validator/semantic_validator.py b/validator/semantic_validator.py new file mode 100644 index 0000000..3269874 --- /dev/null +++ b/validator/semantic_validator.py @@ -0,0 +1,472 @@ +#!/usr/bin/env python3 +import copy +import json +from pathlib import Path + +from jsonschema import Draft202012Validator + + +ROOT = Path(__file__).resolve().parents[1] +SCHEMAS = ROOT / "schemas" + +SCHEMA_INVALID = "SCHEMA_INVALID" +DUPLICATE_MESSAGE_ID = "DUPLICATE_MESSAGE_ID" +HANDSHAKE_ID_MISMATCH = "HANDSHAKE_ID_MISMATCH" +INITIAL_MESSAGE_NOT_PROPOSE = "INITIAL_MESSAGE_NOT_PROPOSE" +PARENT_REQUIRED = "PARENT_REQUIRED" +PARENT_NOT_FOUND = "PARENT_NOT_FOUND" +PARENT_SELF_REFERENCE = "PARENT_SELF_REFERENCE" +PARENT_NOT_EARLIER = "PARENT_NOT_EARLIER" +INVALID_TRANSITION = "INVALID_TRANSITION" +MESSAGE_AFTER_CLOSE = "MESSAGE_AFTER_CLOSE" +CLOSE_BEFORE_AGREE = "CLOSE_BEFORE_AGREE" +CORE_SEMANTIC_REDEFINITION = "CORE_SEMANTIC_REDEFINITION" + +CORE_MESSAGE_TYPES = ("PROPOSE", "CHALLENGE", "AGREE", "CLOSE") +FORBIDDEN_PROFILE_REDEFINITIONS = ( + "PROPOSE", + "CHALLENGE", + "AGREE", + "CLOSE", + "append-only history", + "immutable accepted messages", + "Standard semantics", + "Protocol semantics", +) + + +def validateMessage(message): + errors = _schema_errors("message", message) + errors.extend(_core_redefinition_errors(message)) + return _result(errors) + + +def validateHandshake(handshake): + errors = _schema_errors("handshake", handshake) + + if not isinstance(handshake, dict): + return _result(errors) + + messages = handshake.get("messages") + if not isinstance(messages, list): + return _result(errors) + + for index, message in enumerate(messages): + if isinstance(message, dict): + errors.extend(_message_schema_errors_in_handshake(index, message)) + + handshake_identity = handshake.get("handshakeIdentity") + message_positions = {} + message_ids = [] + + for index, message in enumerate(messages): + if not isinstance(message, dict): + continue + + message_identity = message.get("messageIdentity") + message_ids.append(message_identity) + identity_key = _identity_key(message_identity) + + if identity_key in message_positions: + errors.append( + _error( + DUPLICATE_MESSAGE_ID, + f"messages[{index}].messageIdentity", + "Message identity must be unique within one handshake.", + handshake_identity=handshake_identity, + message_identity=message_identity, + ) + ) + else: + message_positions[identity_key] = index + + if not _same_identity(message.get("handshakeIdentity"), handshake_identity): + errors.append( + _error( + HANDSHAKE_ID_MISMATCH, + f"messages[{index}].handshakeIdentity", + "Message handshake identity must match the enclosing handshake identity.", + handshake_identity=handshake_identity, + message_identity=message_identity, + ) + ) + + errors.extend(_core_redefinition_errors(message, path_prefix=f"messages[{index}]")) + + if messages: + first = messages[0] + first_type = first.get("messageType") if isinstance(first, dict) else None + first_identity = first.get("messageIdentity") if isinstance(first, dict) else None + + if first_type != "PROPOSE": + errors.append( + _error( + INITIAL_MESSAGE_NOT_PROPOSE, + "messages[0].messageType", + "The first accepted message must be PROPOSE.", + handshake_identity=handshake_identity, + message_identity=first_identity, + ) + ) + + parent_map = _parent_map(handshake) + seen_agree = False + closed = False + previous_type = None + + for index, message in enumerate(messages): + if not isinstance(message, dict): + continue + + message_type = message.get("messageType") + message_identity = message.get("messageIdentity") + + if closed: + errors.append( + _error( + MESSAGE_AFTER_CLOSE, + f"messages[{index}].messageType", + "No message may follow CLOSE.", + handshake_identity=handshake_identity, + message_identity=message_identity, + ) + ) + continue + + if index > 0: + parent_refs = _message_parent_refs(message, parent_map) + if not parent_refs: + errors.append( + _error( + PARENT_REQUIRED, + f"messages[{index}].parentReference", + "Every non-initial message must have an applicable parent reference.", + handshake_identity=handshake_identity, + message_identity=message_identity, + ) + ) + + for parent_ref in parent_refs: + parent_key = _identity_key(parent_ref) + if _same_identity(parent_ref, message_identity): + errors.append( + _error( + PARENT_SELF_REFERENCE, + f"messages[{index}].parentReference", + "A message must not reference itself as parent.", + handshake_identity=handshake_identity, + message_identity=message_identity, + ) + ) + continue + + parent_index = message_positions.get(parent_key) + if parent_index is None: + errors.append( + _error( + PARENT_NOT_FOUND, + f"messages[{index}].parentReference", + "A parent reference must identify an accepted message in the same handshake.", + handshake_identity=handshake_identity, + message_identity=message_identity, + ) + ) + continue + + if parent_index >= index: + errors.append( + _error( + PARENT_NOT_EARLIER, + f"messages[{index}].parentReference", + "A parent reference must identify an earlier accepted message.", + handshake_identity=handshake_identity, + message_identity=message_identity, + ) + ) + + transition_error = _transition_error(previous_type, message_type, index, seen_agree, handshake) + if transition_error: + code, message_text = transition_error + errors.append( + _error( + code, + f"messages[{index}].messageType", + message_text, + handshake_identity=handshake_identity, + message_identity=message_identity, + ) + ) + + if message_type == "AGREE": + seen_agree = True + + if message_type == "CLOSE": + closed = True + + previous_type = message_type + + return _result(errors) + + +def validateProfile(profile): + errors = _schema_errors("profile", profile) + errors.extend(_profile_redefinition_errors(profile)) + return _result(errors) + + +def _result(errors): + return { + "valid": not errors, + "errors": errors, + } + + +def _load_json(path): + return json.loads(path.read_text(encoding="utf-8")) + + +def _schema_for(kind): + if kind == "message": + return _load_json(SCHEMAS / "message.schema.json") + if kind == "profile": + return _load_json(SCHEMAS / "profile.schema.json") + if kind == "handshake": + schema = _load_json(SCHEMAS / "handshake.schema.json") + schema = copy.deepcopy(schema) + schema["properties"]["messages"]["items"] = {"type": "object"} + return schema + raise ValueError(f"Unknown schema kind: {kind}") + + +def _schema_errors(kind, instance): + schema = _schema_for(kind) + validator = Draft202012Validator(schema) + errors = [] + + for schema_error in sorted(validator.iter_errors(instance), key=_schema_error_sort_key): + errors.append( + _error( + SCHEMA_INVALID, + _schema_path(schema_error), + f"Schema validation failed: {schema_error.message}", + handshake_identity=_context_value(instance, "handshakeIdentity"), + message_identity=_context_value(instance, "messageIdentity"), + ) + ) + + return errors + + +def _message_schema_errors_in_handshake(index, message): + errors = _schema_errors("message", message) + for error in errors: + error["path"] = _prefix_path(f"$.messages[{index}]", error["path"]) + return errors + + +def _schema_error_sort_key(schema_error): + return (list(schema_error.path), schema_error.message) + + +def _schema_path(schema_error): + parts = list(schema_error.path) + if not parts: + return "$" + + path = "$" + for part in parts: + if isinstance(part, int): + path += f"[{part}]" + else: + path += f".{part}" + return path + + +def _prefix_path(prefix, path): + if path == "$": + return prefix + if path.startswith("$."): + return prefix + path[1:] + if path.startswith("$["): + return prefix + path[1:] + return f"{prefix}.{path}" + + +def _context_value(value, key): + if isinstance(value, dict): + return value.get(key) + return None + + +def _error(code, path, message, handshake_identity=None, message_identity=None): + error = { + "code": code, + "path": path, + "message": message, + } + + if message_identity is not None: + error["messageIdentity"] = message_identity + + if handshake_identity is not None: + error["handshakeIdentity"] = handshake_identity + + return error + + +def _identity_key(value): + return json.dumps(value, sort_keys=True, separators=(",", ":")) + + +def _same_identity(left, right): + return _identity_key(left) == _identity_key(right) + + +def _parent_map(handshake): + parent_map = {} + relationships = handshake.get("parentRelationships", []) + if not isinstance(relationships, list): + return parent_map + + for relationship in relationships: + if not isinstance(relationship, dict): + continue + message_ref = relationship.get("messageReference") + parent_ref = relationship.get("parentReference") + if message_ref is None or parent_ref is None: + continue + parent_map.setdefault(_identity_key(message_ref), []).append(parent_ref) + + return parent_map + + +def _message_parent_refs(message, parent_map): + parent_refs = [] + if "parentReference" in message: + parent_refs.append(message.get("parentReference")) + + message_identity = message.get("messageIdentity") + parent_refs.extend(parent_map.get(_identity_key(message_identity), [])) + + unique_refs = [] + seen = set() + for parent_ref in parent_refs: + key = _identity_key(parent_ref) + if key in seen: + continue + seen.add(key) + unique_refs.append(parent_ref) + + return unique_refs + + +def _transition_error(previous_type, message_type, index, seen_agree, handshake): + if message_type not in CORE_MESSAGE_TYPES: + return None + + if index == 0: + return None + + if message_type == "PROPOSE": + if previous_type == "CHALLENGE": + return None + return ( + INVALID_TRANSITION, + "A revised PROPOSE is only valid after CHALLENGE in this bounded validator.", + ) + + if message_type == "CHALLENGE": + if previous_type in ("PROPOSE", "CHALLENGE"): + return None + return ( + INVALID_TRANSITION, + "CHALLENGE must follow proposal or challenge context.", + ) + + if message_type == "AGREE": + if previous_type == "CHALLENGE": + return None + return ( + INVALID_TRANSITION, + "AGREE must follow resolved negotiation context.", + ) + + if message_type == "CLOSE": + outcome = _terminal_outcome(handshake) + if outcome == "completed" and not seen_agree: + return ( + CLOSE_BEFORE_AGREE, + "A completed CLOSE must not appear before AGREE.", + ) + if outcome == "completed" and previous_type != "AGREE": + return ( + INVALID_TRANSITION, + "A completed CLOSE must follow AGREE.", + ) + return None + + return None + + +def _terminal_outcome(handshake): + terminal = handshake.get("terminalClosure") + if isinstance(terminal, dict): + return terminal.get("outcome") + return None + + +def _core_redefinition_errors(value, path_prefix="$"): + errors = [] + _walk_for_redefinitions(value, path_prefix, errors, profile_mode=False) + return errors + + +def _profile_redefinition_errors(profile): + errors = [] + _walk_for_redefinitions(profile, "$", errors, profile_mode=True) + return errors + + +def _walk_for_redefinitions(value, path, errors, profile_mode): + if isinstance(value, dict): + if "messageTypeRedefinitions" in value: + errors.append( + _error( + CORE_SEMANTIC_REDEFINITION, + _join_path(path, "messageTypeRedefinitions"), + "Extensions may not masquerade as replacement canonical message types.", + handshake_identity=value.get("handshakeIdentity"), + message_identity=value.get("messageIdentity"), + ) + ) + + if profile_mode and path.endswith(".terminology"): + for core_type in CORE_MESSAGE_TYPES: + if core_type in value: + errors.append( + _error( + CORE_SEMANTIC_REDEFINITION, + _join_path(path, core_type), + "Profiles must not redefine canonical message types.", + ) + ) + + for key in FORBIDDEN_PROFILE_REDEFINITIONS: + if key in value and key != "PROPOSE" and not path.endswith(".terminology"): + # Canonical terms can appear as data elsewhere; only explicit + # redefinition containers are rejected by this bounded pass. + continue + + for child_key, child_value in value.items(): + _walk_for_redefinitions(child_value, _join_path(path, child_key), errors, profile_mode) + return + + if isinstance(value, list): + for index, child_value in enumerate(value): + _walk_for_redefinitions(child_value, f"{path}[{index}]", errors, profile_mode) + + +def _join_path(path, part): + if path == "$": + return f"$.{part}" + return f"{path}.{part}" From 96d15ee9cb27e30d0b9b25878b2bff9741346f2b Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 02:53:36 +0800 Subject: [PATCH 02/18] Refine SDK ergonomics and fixture round trips --- passpod/errors.py | 10 +- passpod/handshake.py | 42 +++++- passpod/message.py | 10 +- passpod/profile.py | 10 +- tests/test_sdk_fixture_roundtrip.py | 226 ++++++++++++++++++++++++++++ 5 files changed, 293 insertions(+), 5 deletions(-) create mode 100644 tests/test_sdk_fixture_roundtrip.py diff --git a/passpod/errors.py b/passpod/errors.py index 2b1d116..7d14019 100644 --- a/passpod/errors.py +++ b/passpod/errors.py @@ -1,11 +1,18 @@ +from types import MappingProxyType + + class PasspodValidationError(ValueError): """SDK-facing validation failure with deterministic validator errors.""" def __init__(self, operation, errors): self.operation = operation - self.errors = tuple(_copy_error(error) for error in errors) + self._errors = tuple(MappingProxyType(_copy_error(error)) for error in errors) super().__init__(self._summary()) + @property + def errors(self): + return tuple(dict(error) for error in self._errors) + def _summary(self): if not self.errors: return f"{self.operation} failed validation" @@ -18,4 +25,3 @@ def _copy_error(error): if isinstance(error, dict): return dict(error) return {"code": "UNKNOWN", "path": "$", "message": str(error)} - diff --git a/passpod/handshake.py b/passpod/handshake.py index ea9092e..5ef745a 100644 --- a/passpod/handshake.py +++ b/passpod/handshake.py @@ -1,5 +1,6 @@ from copy import deepcopy from dataclasses import dataclass +import json from validator.semantic_validator import validateHandshake @@ -49,24 +50,52 @@ def __init__( data[key] = deepcopy(value) object.__setattr__(self, "_data", data) + self._set_history() if self._data.get("messages"): self.validate() + def __repr__(self): + return ( + "Handshake(" + f"handshake_identity={self.handshake_identity!r}, " + f"state={self.lifecycle!r}, " + f"message_count={self.message_count!r}" + ")" + ) + @classmethod def from_mapping(cls, mapping): instance = cls.__new__(cls) object.__setattr__(instance, "_data", deepcopy(dict(mapping))) + instance._set_history() if instance._data.get("messages"): instance.validate() return instance + def _set_history(self): + object.__setattr__( + self, + "_history", + tuple(Message.from_mapping(message) for message in self._data.get("messages", [])), + ) + @property def handshake_identity(self): return deepcopy(self._data.get("handshakeIdentity")) @property def history(self): - return tuple(Message.from_mapping(message) for message in self._data.get("messages", [])) + return self._history + + @property + def message_count(self): + return len(self._history) + + @property + def last_message(self): + if not self._history: + return None + return self._history[-1] @property def lifecycle(self): @@ -94,6 +123,13 @@ def append(self, message): candidate["messages"].append(_message_mapping(message)) return self.from_mapping(candidate) + def get_message(self, message_identity): + expected = _identity_key(message_identity) + for message in self._history: + if _identity_key(message.message_identity) == expected: + return message + return None + def to_mapping(self): return deepcopy(self._data) @@ -111,3 +147,7 @@ def _message_mapping(message): if isinstance(message, Message): return message.to_mapping() return deepcopy(dict(message)) + + +def _identity_key(value): + return json.dumps(value, sort_keys=True, separators=(",", ":")) diff --git a/passpod/message.py b/passpod/message.py index 9f525c7..7174773 100644 --- a/passpod/message.py +++ b/passpod/message.py @@ -48,6 +48,15 @@ def __init__( object.__setattr__(self, "_data", data) self.validate() + def __repr__(self): + return ( + "Message(" + f"message_identity={self.message_identity!r}, " + f"message_type={self.message_type!r}, " + f"handshake_identity={self.handshake_identity!r}" + ")" + ) + @classmethod def from_mapping(cls, mapping): instance = cls.__new__(cls) @@ -87,4 +96,3 @@ def validate(self): if not result.get("valid"): raise PasspodValidationError("validateMessage", result.get("errors", [])) return result - diff --git a/passpod/profile.py b/passpod/profile.py index d4d1df2..3a271cb 100644 --- a/passpod/profile.py +++ b/passpod/profile.py @@ -40,6 +40,15 @@ def __init__( object.__setattr__(self, "_data", data) self.validate() + def __repr__(self): + return ( + "Profile(" + f"profile_identity={self.profile_identity!r}, " + f"profile_version={self.profile_version!r}, " + f"lifecycle={self.lifecycle!r}" + ")" + ) + @classmethod def from_mapping(cls, mapping): instance = cls.__new__(cls) @@ -67,4 +76,3 @@ def validate(self): if not result.get("valid"): raise PasspodValidationError("validateProfile", result.get("errors", [])) return result - diff --git a/tests/test_sdk_fixture_roundtrip.py b/tests/test_sdk_fixture_roundtrip.py new file mode 100644 index 0000000..f040ba8 --- /dev/null +++ b/tests/test_sdk_fixture_roundtrip.py @@ -0,0 +1,226 @@ +import json +import unittest +from pathlib import Path + +from passpod import Handshake, Message, PasspodValidationError, Profile +from validator.semantic_validator import validateHandshake, validateMessage, validateProfile + + +ROOT = Path(__file__).resolve().parents[1] + + +EXPECTED_INVALID_CODES = { + "close-before-agree.json": "CLOSE_BEFORE_AGREE", + "duplicate-message-id.json": "DUPLICATE_MESSAGE_ID", + "invalid-transition.json": "INVALID_TRANSITION", + "missing-parent.json": "PARENT_REQUIRED", + "redefine-message-type.json": "CORE_SEMANTIC_REDEFINITION", +} + + +def load_json(path): + return json.loads(path.read_text(encoding="utf-8")) + + +def sdk_from_mapping(mapping): + if "profileIdentity" in mapping: + return Profile.from_mapping(mapping) + if "messages" in mapping: + return Handshake.from_mapping(mapping) + return Message.from_mapping(mapping) + + +def validate_mapping(mapping): + if "profileIdentity" in mapping: + return validateProfile(mapping) + if "messages" in mapping: + return validateHandshake(mapping) + return validateMessage(mapping) + + +def error_codes(error): + return [entry["code"] for entry in error.errors] + + +class FixtureRoundTripTests(unittest.TestCase): + def test_all_valid_fixtures_round_trip_and_validate(self): + for path in sorted((ROOT / "examples" / "valid").glob("*.json")): + with self.subTest(path=path.name): + original = load_json(path) + sdk_object = sdk_from_mapping(original) + round_tripped = sdk_object.to_mapping() + + self.assertEqual(original, round_tripped) + self.assertIsNot(original, round_tripped) + + result = validate_mapping(round_tripped) + self.assertTrue(result["valid"], result["errors"]) + + def test_all_invalid_fixtures_fail_with_intended_error_codes(self): + for path in sorted((ROOT / "examples" / "invalid").glob("*.json")): + with self.subTest(path=path.name): + original = load_json(path) + + with self.assertRaises(PasspodValidationError) as raised: + sdk_from_mapping(original) + + self.assertIn(EXPECTED_INVALID_CODES[path.name], error_codes(raised.exception)) + + +class ErgonomicsTests(unittest.TestCase): + def test_reprs_are_readable_and_bounded(self): + message = Message.from_mapping( + { + "messageIdentity": "msg-repr-001", + "handshakeIdentity": "hs-repr-001", + "messageType": "PROPOSE", + "sender": "participant-alpha", + "evidenceReferences": ["sensitive-evidence-reference"], + "extensions": {"largePayload": {"nested": "payload"}}, + } + ) + handshake = Handshake.from_mapping(load_json(ROOT / "examples" / "valid" / "complete-handshake.json")) + profile = Profile.from_mapping(load_json(ROOT / "examples" / "valid" / "minimal-profile.json")) + + self.assertEqual( + "Message(message_identity='msg-repr-001', message_type='PROPOSE', handshake_identity='hs-repr-001')", + repr(message), + ) + self.assertIn("Handshake(handshake_identity='hs-complete-001'", repr(handshake)) + self.assertIn("state='closed'", repr(handshake)) + self.assertIn("message_count=4", repr(handshake)) + self.assertEqual( + "Profile(profile_identity='profile-minimal-001', profile_version='0.1', lifecycle='draft')", + repr(profile), + ) + self.assertNotIn("sensitive-evidence-reference", repr(message)) + self.assertNotIn("largePayload", repr(message)) + + def test_handshake_read_only_conveniences(self): + empty = Handshake("hs-empty-001") + self.assertEqual(0, empty.message_count) + self.assertIsNone(empty.last_message) + self.assertIsNone(empty.get_message("missing")) + + handshake = Handshake.from_mapping(load_json(ROOT / "examples" / "valid" / "complete-handshake.json")) + last = handshake.last_message + + self.assertEqual(4, handshake.message_count) + self.assertIs(last, handshake.get_message("msg-close-001")) + self.assertEqual("CLOSE", last.message_type) + self.assertIsNone(handshake.get_message("missing")) + + def test_equivalent_value_objects_compare_equal(self): + message_mapping = load_json(ROOT / "examples" / "valid" / "minimal-propose.json") + handshake_mapping = load_json(ROOT / "examples" / "valid" / "complete-handshake.json") + profile_mapping = load_json(ROOT / "examples" / "valid" / "minimal-profile.json") + + self.assertEqual(Message.from_mapping(message_mapping), Message.from_mapping(message_mapping)) + self.assertEqual(Handshake.from_mapping(handshake_mapping), Handshake.from_mapping(handshake_mapping)) + self.assertEqual(Profile.from_mapping(profile_mapping), Profile.from_mapping(profile_mapping)) + + +class DefensiveCopyTests(unittest.TestCase): + def test_original_mapping_mutation_does_not_affect_sdk_object(self): + mapping = { + "messageIdentity": "msg-copy-001", + "handshakeIdentity": "hs-copy-001", + "messageType": "PROPOSE", + "sender": {"id": "participant-alpha"}, + "extensions": {"nested": {"value": "accepted"}}, + } + message = Message.from_mapping(mapping) + + mapping["sender"]["id"] = "changed" + mapping["extensions"]["nested"]["value"] = "changed" + + self.assertEqual({"id": "participant-alpha"}, message.sender) + self.assertEqual("accepted", message.to_mapping()["extensions"]["nested"]["value"]) + + def test_to_mapping_mutation_does_not_affect_sdk_object(self): + message = Message.from_mapping( + { + "messageIdentity": "msg-copy-002", + "handshakeIdentity": "hs-copy-002", + "messageType": "PROPOSE", + "sender": "participant-alpha", + "evidenceReferences": [{"id": "evidence-001"}], + "extensions": {"nested": {"value": "accepted"}}, + } + ) + + exported = message.to_mapping() + exported["evidenceReferences"][0]["id"] = "changed" + exported["extensions"]["nested"]["value"] = "changed" + + fresh = message.to_mapping() + self.assertEqual("evidence-001", fresh["evidenceReferences"][0]["id"]) + self.assertEqual("accepted", fresh["extensions"]["nested"]["value"]) + + def test_handshake_history_cannot_be_changed_through_returned_collections(self): + handshake = Handshake.from_mapping(load_json(ROOT / "examples" / "valid" / "complete-handshake.json")) + history = handshake.history + + with self.assertRaises(AttributeError): + history.append(Message.from_mapping(load_json(ROOT / "examples" / "valid" / "minimal-propose.json"))) + + exported = handshake.to_mapping() + exported["messages"].reverse() + + self.assertEqual("msg-propose-001", handshake.history[0].message_identity) + self.assertEqual("msg-close-001", handshake.last_message.message_identity) + + def test_prior_handshake_remains_unchanged_after_append(self): + initial = Message.from_mapping(load_json(ROOT / "examples" / "valid" / "minimal-propose.json")) + proposed = Handshake("hs-minimal-propose-001", messages=[initial]).append( + Message.from_mapping( + { + "messageIdentity": "msg-challenge-001", + "handshakeIdentity": "hs-minimal-propose-001", + "parentReference": "msg-propose-001", + "messageType": "CHALLENGE", + "sender": "participant-beta", + } + ) + ) + agreed = proposed.append( + Message.from_mapping( + { + "messageIdentity": "msg-agree-001", + "handshakeIdentity": "hs-minimal-propose-001", + "parentReference": "msg-challenge-001", + "messageType": "AGREE", + "sender": "participant-alpha", + } + ) + ) + + self.assertEqual(2, proposed.message_count) + self.assertEqual(3, agreed.message_count) + self.assertEqual("CHALLENGE", proposed.last_message.message_type) + self.assertEqual("AGREE", agreed.last_message.message_type) + + +class ExceptionErgonomicsTests(unittest.TestCase): + def test_error_access_is_defensive_and_string_is_readable(self): + with self.assertRaises(PasspodValidationError) as raised: + Message.from_mapping( + { + "messageIdentity": "msg-error-001", + "handshakeIdentity": "hs-error-001", + "messageType": "UNKNOWN", + "sender": "participant-alpha", + } + ) + + error = raised.exception + errors = error.errors + errors[0]["code"] = "MUTATED" + + self.assertEqual("validateMessage", error.operation) + self.assertIn("validateMessage failed validation: SCHEMA_INVALID", str(error)) + self.assertEqual("SCHEMA_INVALID", error.errors[0]["code"]) + + +if __name__ == "__main__": + unittest.main() From 3118802e3fe070778c4b6ce31e5548a70a72a057 Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 02:59:49 +0800 Subject: [PATCH 03/18] Add minimal Passpod validate and inspect CLI --- passpod/cli.py | 241 ++++++++++++++++++++++++++++++++++++++++++++ tests/test_cli.py | 249 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 490 insertions(+) create mode 100644 passpod/cli.py create mode 100644 tests/test_cli.py diff --git a/passpod/cli.py b/passpod/cli.py new file mode 100644 index 0000000..e0e937e --- /dev/null +++ b/passpod/cli.py @@ -0,0 +1,241 @@ +import argparse +import json +import sys + +from . import Handshake, Message, PasspodValidationError, Profile + + +EXIT_SUCCESS = 0 +EXIT_INVALID = 1 +EXIT_INPUT_ERROR = 2 + +FILE_NOT_FOUND = "FILE_NOT_FOUND" +FILE_READ_ERROR = "FILE_READ_ERROR" +JSON_INVALID = "JSON_INVALID" +ROOT_NOT_OBJECT = "ROOT_NOT_OBJECT" +ARTIFACT_TYPE_UNKNOWN = "ARTIFACT_TYPE_UNKNOWN" +ARTIFACT_TYPE_AMBIGUOUS = "ARTIFACT_TYPE_AMBIGUOUS" + + +class CliError(Exception): + def __init__(self, code, message): + self.code = code + self.message = message + super().__init__(message) + + +def main(argv=None): + parser = _build_parser() + args = parser.parse_args(argv) + + try: + mapping = _load_mapping(args.path) + artifact_type = detect_artifact_type(mapping) + except CliError as error: + return _emit_cli_error(error, args.json) + + if args.command == "validate": + return _validate(artifact_type, mapping, args.json) + if args.command == "inspect": + return _inspect(artifact_type, mapping, args.json) + + parser.error(f"unsupported command: {args.command}") + return EXIT_INPUT_ERROR + + +def _build_parser(): + parser = argparse.ArgumentParser(prog="python3 -m passpod.cli") + subparsers = parser.add_subparsers(dest="command", required=True) + + for command in ("validate", "inspect"): + subparser = subparsers.add_parser(command) + subparser.add_argument("path") + subparser.add_argument("--json", action="store_true", dest="json") + + return parser + + +def _load_mapping(path): + try: + with open(path, "r", encoding="utf-8") as handle: + value = json.load(handle) + except FileNotFoundError as error: + raise CliError(FILE_NOT_FOUND, "File was not found.") from error + except json.JSONDecodeError as error: + message = f"JSON is malformed at line {error.lineno}, column {error.colno}." + raise CliError(JSON_INVALID, message) from error + except OSError as error: + raise CliError(FILE_READ_ERROR, "File could not be read.") from error + + if not isinstance(value, dict): + raise CliError(ROOT_NOT_OBJECT, "JSON root must be an object.") + + return value + + +def detect_artifact_type(mapping): + matches = [] + + if {"messageIdentity", "messageType"}.issubset(mapping): + matches.append("message") + if {"handshakeIdentity", "messages"}.issubset(mapping): + matches.append("handshake") + if {"profileIdentity", "profileVersion", "lifecycle"}.issubset(mapping): + matches.append("profile") + + if len(matches) == 1: + return matches[0] + if not matches: + raise CliError(ARTIFACT_TYPE_UNKNOWN, "Artifact type could not be determined.") + + raise CliError( + ARTIFACT_TYPE_AMBIGUOUS, + "Artifact matches multiple top-level artifact shapes.", + ) + + +def _validate(artifact_type, mapping, as_json): + try: + _construct_object(artifact_type, mapping) + except PasspodValidationError as error: + return _emit_validation_failure(artifact_type, error.errors, as_json) + + payload = { + "valid": True, + "artifact_type": artifact_type, + "errors": [], + } + if as_json: + _write_json(sys.stdout, payload) + else: + print(f"VALID {artifact_type}") + return EXIT_SUCCESS + + +def _inspect(artifact_type, mapping, as_json): + try: + value = _construct_object(artifact_type, mapping) + except PasspodValidationError as error: + return _emit_validation_failure(artifact_type, error.errors, as_json) + + summary = _summary(artifact_type, value) + if as_json: + _write_json(sys.stdout, summary) + else: + _write_human_summary(summary) + return EXIT_SUCCESS + + +def _construct_object(artifact_type, mapping): + if artifact_type == "message": + return Message.from_mapping(mapping) + if artifact_type == "handshake": + return Handshake.from_mapping(mapping) + if artifact_type == "profile": + return Profile.from_mapping(mapping) + raise CliError(ARTIFACT_TYPE_UNKNOWN, "Artifact type could not be determined.") + + +def _summary(artifact_type, value): + if artifact_type == "message": + return { + "artifact_type": "message", + "message_identity": value.message_identity, + "handshake_identity": value.handshake_identity, + "message_type": value.message_type, + "parent_reference": value.parent_reference, + "sender_present": value.sender is not None, + "recipient_present": value.recipient is not None, + } + + if artifact_type == "handshake": + return { + "artifact_type": "handshake", + "handshake_identity": value.handshake_identity, + "state": value.lifecycle, + "closed": value.is_closed, + "message_count": value.message_count, + "messages": [ + { + "message_identity": message.message_identity, + "message_type": message.message_type, + } + for message in value.history + ], + } + + if artifact_type == "profile": + return { + "artifact_type": "profile", + "profile_identity": value.profile_identity, + "profile_version": value.profile_version, + "lifecycle": value.lifecycle, + } + + raise CliError(ARTIFACT_TYPE_UNKNOWN, "Artifact type could not be determined.") + + +def _emit_validation_failure(artifact_type, errors, as_json): + payload = { + "valid": False, + "artifact_type": artifact_type, + "errors": list(errors), + } + if as_json: + _write_json(sys.stderr, payload) + else: + print(f"INVALID {artifact_type}", file=sys.stderr) + for error in errors: + code = error.get("code", "UNKNOWN") + path = error.get("path", "$") + message = error.get("message", "") + print(f"{code} {path}: {message}", file=sys.stderr) + return EXIT_INVALID + + +def _emit_cli_error(error, as_json): + payload = { + "valid": False, + "artifact_type": None, + "errors": [ + { + "code": error.code, + "path": "$", + "message": error.message, + } + ], + } + if as_json: + _write_json(sys.stderr, payload) + else: + print(f"ERROR {error.code}: {error.message}", file=sys.stderr) + return EXIT_INPUT_ERROR + + +def _write_human_summary(summary): + for key, value in summary.items(): + if key == "messages": + print("messages:") + for message in value: + print(f"- {_format_value(message['message_identity'])} {_format_value(message['message_type'])}") + else: + print(f"{key}: {_format_value(value)}") + + +def _write_json(stream, payload): + stream.write(json.dumps(payload, sort_keys=True, separators=(",", ":"))) + stream.write("\n") + + +def _format_value(value): + if isinstance(value, bool): + return "true" if value else "false" + if value is None: + return "null" + if isinstance(value, (dict, list)): + return json.dumps(value, sort_keys=True, separators=(",", ":")) + return str(value) + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..bfa04d7 --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,249 @@ +import json +import os +import subprocess +import sys +import tempfile +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +EXPECTED_INVALID_CODES = { + "close-before-agree.json": "CLOSE_BEFORE_AGREE", + "duplicate-message-id.json": "DUPLICATE_MESSAGE_ID", + "invalid-transition.json": "INVALID_TRANSITION", + "missing-parent.json": "PARENT_REQUIRED", + "redefine-message-type.json": "CORE_SEMANTIC_REDEFINITION", +} + + +def run_cli(*args): + env = os.environ.copy() + env["PYTHONDONTWRITEBYTECODE"] = "1" + return subprocess.run( + [sys.executable, "-m", "passpod.cli", *args], + cwd=ROOT, + env=env, + text=True, + capture_output=True, + check=False, + ) + + +def write_json(directory, name, value): + path = Path(directory) / name + path.write_text(json.dumps(value), encoding="utf-8") + return path + + +def assert_no_traceback(test_case, result): + test_case.assertNotIn("Traceback", result.stdout) + test_case.assertNotIn("Traceback", result.stderr) + + +class ValidateCommandTests(unittest.TestCase): + def test_validate_human_success_for_supported_artifacts(self): + cases = [ + ("message", ROOT / "examples" / "valid" / "minimal-propose.json"), + ("handshake", ROOT / "examples" / "valid" / "complete-handshake.json"), + ("profile", ROOT / "examples" / "valid" / "minimal-profile.json"), + ] + + for artifact_type, path in cases: + with self.subTest(artifact_type=artifact_type): + result = run_cli("validate", str(path)) + + self.assertEqual(0, result.returncode, result.stderr) + self.assertEqual(f"VALID {artifact_type}\n", result.stdout) + self.assertEqual("", result.stderr) + + def test_validate_json_success(self): + result = run_cli( + "validate", + str(ROOT / "examples" / "valid" / "complete-handshake.json"), + "--json", + ) + + self.assertEqual(0, result.returncode, result.stderr) + self.assertEqual( + { + "valid": True, + "artifact_type": "handshake", + "errors": [], + }, + json.loads(result.stdout), + ) + self.assertEqual("", result.stderr) + + def test_validate_semantic_failures_preserve_validator_codes(self): + for path in sorted((ROOT / "examples" / "invalid").glob("*.json")): + with self.subTest(path=path.name): + result = run_cli("validate", str(path)) + + self.assertEqual(1, result.returncode) + self.assertEqual("", result.stdout) + self.assertIn("INVALID ", result.stderr) + self.assertIn(EXPECTED_INVALID_CODES[path.name], result.stderr) + assert_no_traceback(self, result) + + def test_validate_json_semantic_failure_preserves_validator_errors(self): + result = run_cli( + "validate", + str(ROOT / "examples" / "invalid" / "missing-parent.json"), + "--json", + ) + + payload = json.loads(result.stderr) + self.assertEqual(1, result.returncode) + self.assertEqual("", result.stdout) + self.assertFalse(payload["valid"]) + self.assertEqual("handshake", payload["artifact_type"]) + self.assertIn("PARENT_REQUIRED", [error["code"] for error in payload["errors"]]) + assert_no_traceback(self, result) + + +class InputFailureTests(unittest.TestCase): + def test_detection_and_input_failures_are_exit_code_2(self): + with tempfile.TemporaryDirectory() as directory: + malformed = Path(directory) / "malformed.json" + malformed.write_text("{", encoding="utf-8") + non_object = Path(directory) / "non-object.json" + non_object.write_text("[]", encoding="utf-8") + unknown = write_json(directory, "unknown.json", {"hello": "world"}) + ambiguous = write_json( + directory, + "ambiguous.json", + { + "messageIdentity": "msg-ambiguous-001", + "messageType": "PROPOSE", + "profileIdentity": "profile-ambiguous-001", + "profileVersion": "0.1", + "lifecycle": "draft", + }, + ) + + cases = [ + ("FILE_NOT_FOUND", Path(directory) / "missing.json"), + ("JSON_INVALID", malformed), + ("ROOT_NOT_OBJECT", non_object), + ("ARTIFACT_TYPE_UNKNOWN", unknown), + ("ARTIFACT_TYPE_AMBIGUOUS", ambiguous), + ] + + for code, path in cases: + with self.subTest(code=code): + result = run_cli("validate", str(path)) + + self.assertEqual(2, result.returncode) + self.assertEqual("", result.stdout) + self.assertIn(code, result.stderr) + assert_no_traceback(self, result) + + def test_json_input_failure_uses_cli_error_code(self): + with tempfile.TemporaryDirectory() as directory: + path = write_json(directory, "unknown.json", {"hello": "world"}) + + result = run_cli("validate", str(path), "--json") + + payload = json.loads(result.stderr) + self.assertEqual(2, result.returncode) + self.assertEqual("", result.stdout) + self.assertEqual("ARTIFACT_TYPE_UNKNOWN", payload["errors"][0]["code"]) + self.assertIsNone(payload["artifact_type"]) + assert_no_traceback(self, result) + + +class InspectCommandTests(unittest.TestCase): + def test_inspect_message_human_summary(self): + result = run_cli("inspect", str(ROOT / "examples" / "valid" / "minimal-propose.json")) + + self.assertEqual(0, result.returncode, result.stderr) + self.assertEqual("", result.stderr) + self.assertIn("artifact_type: message\n", result.stdout) + self.assertIn("message_identity: msg-propose-001\n", result.stdout) + self.assertIn("handshake_identity: hs-minimal-propose-001\n", result.stdout) + self.assertIn("message_type: PROPOSE\n", result.stdout) + self.assertIn("parent_reference: null\n", result.stdout) + self.assertIn("sender_present: true\n", result.stdout) + self.assertIn("recipient_present: false\n", result.stdout) + + def test_inspect_handshake_json_summary(self): + result = run_cli( + "inspect", + str(ROOT / "examples" / "valid" / "complete-handshake.json"), + "--json", + ) + + payload = json.loads(result.stdout) + self.assertEqual(0, result.returncode, result.stderr) + self.assertEqual("", result.stderr) + self.assertEqual("handshake", payload["artifact_type"]) + self.assertEqual("closed", payload["state"]) + self.assertTrue(payload["closed"]) + self.assertEqual(4, payload["message_count"]) + self.assertEqual( + [ + {"message_identity": "msg-propose-001", "message_type": "PROPOSE"}, + {"message_identity": "msg-challenge-001", "message_type": "CHALLENGE"}, + {"message_identity": "msg-agree-001", "message_type": "AGREE"}, + {"message_identity": "msg-close-001", "message_type": "CLOSE"}, + ], + payload["messages"], + ) + + def test_inspect_profile_human_summary(self): + result = run_cli("inspect", str(ROOT / "examples" / "valid" / "minimal-profile.json")) + + self.assertEqual(0, result.returncode, result.stderr) + self.assertEqual("", result.stderr) + self.assertIn("artifact_type: profile\n", result.stdout) + self.assertIn("profile_identity: profile-minimal-001\n", result.stdout) + self.assertIn("profile_version: 0.1\n", result.stdout) + self.assertIn("lifecycle: draft\n", result.stdout) + self.assertNotIn("Minimal Profile Model Example", result.stdout) + + def test_inspect_rejects_invalid_artifact(self): + result = run_cli("inspect", str(ROOT / "examples" / "invalid" / "invalid-transition.json")) + + self.assertEqual(1, result.returncode) + self.assertEqual("", result.stdout) + self.assertIn("INVALID handshake", result.stderr) + self.assertIn("INVALID_TRANSITION", result.stderr) + assert_no_traceback(self, result) + + +class InspectPrivacyTests(unittest.TestCase): + def test_inspect_does_not_expose_sensitive_payloads(self): + with tempfile.TemporaryDirectory() as directory: + path = write_json( + directory, + "private-message.json", + { + "messageIdentity": "msg-private-001", + "handshakeIdentity": "hs-private-001", + "messageType": "PROPOSE", + "sender": {"id": "participant-alpha", "secret": "sender-secret"}, + "recipient": {"id": "participant-beta", "secret": "recipient-secret"}, + "evidenceReferences": [{"secretEvidence": "evidence-secret"}], + "extensions": {"privateExtension": "extension-secret"}, + }, + ) + + human = run_cli("inspect", str(path)) + machine = run_cli("inspect", str(path), "--json") + combined = human.stdout + human.stderr + machine.stdout + machine.stderr + + self.assertEqual(0, human.returncode, human.stderr) + self.assertEqual(0, machine.returncode, machine.stderr) + self.assertIn("sender_present: true", human.stdout) + self.assertIn("recipient_present: true", human.stdout) + self.assertNotIn("sender-secret", combined) + self.assertNotIn("recipient-secret", combined) + self.assertNotIn("evidence-secret", combined) + self.assertNotIn("extension-secret", combined) + + +if __name__ == "__main__": + unittest.main() From 35699ea7fbe701a0f996f8bc74ebf77f1b60cb35 Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 03:10:29 +0800 Subject: [PATCH 04/18] Migrate README and quickstart to Passpod v0.1 --- README.md | 215 +++++++++++++++++++++++++++++++++++++-------- docs/QUICKSTART.md | 105 ++++++++++++++++++++++ 2 files changed, 284 insertions(+), 36 deletions(-) create mode 100644 docs/QUICKSTART.md diff --git a/README.md b/README.md index 3596baf..1d1c087 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,201 @@ -# Passpod TASK Core +# Passpod + +Passpod is a transport-neutral standard and handshake protocol for structured trust negotiation. + +It defines a small shared model for participants to propose meaning, request clarification or evidence, record agreement, and close negotiation without binding the protocol to a specific transport, storage system, identity system, or runtime. + +## Core Idea + +The canonical Passpod handshake is: + +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` + +- `PROPOSE`: states what a participant wants to establish. +- `CHALLENGE`: requests clarification, evidence, constraints, or revision. +- `AGREE`: records acceptance of the negotiated meaning. +- `CLOSE`: records the terminal outcome and ends active negotiation. + +A handshake is append-only. Accepted messages are immutable. Later messages may clarify, qualify, or close prior negotiation meaning, but they do not rewrite accepted history. + +## Why Passpod + +Digital workflows often exchange data without a shared negotiation model. Domain-specific systems frequently reinvent proposal, challenge, agreement, and closure semantics, which makes interoperability harder than it needs to be. + +Passpod provides a small interoperable core. Profiles allow domain specialization without forking or redefining the protocol. + +## Architecture + +Normative architecture documents: -[![Validate TASK public repo](https://github.com/edidx/passpod-task/actions/workflows/validate.yml/badge.svg)](https://github.com/edidx/passpod-task/actions/workflows/validate.yml) +- [Passpod Standard](docs/STANDARD.md): semantic authority for Passpod. +- [Passpod Handshake Protocol](docs/PROTOCOL.md): transport-neutral negotiation flow. +- [State Model](docs/STATE-MODEL.md): conceptual message and handshake lifecycles. +- [Message Model](docs/MESSAGE-MODEL.md): conceptual relationships among messages, handshakes, participants, profiles, evidence, references, versions, and extensions. +- [Profiles](docs/PROFILES.md): domain-specific specialization model. +- [Conformance](docs/CONFORMANCE.md): alignment requirements for documents, profiles, SDKs, validators, CLIs, and related materials. +- [Terminology](docs/TERMINOLOGY.md): active terminology and archived legacy terminology. +- [Specification Freeze Report](docs/SPECIFICATION_FREEZE_REPORT.md): consistency audit for Passpod Specification v0.1. + +Implementation tooling: + +- [Schemas](schemas): machine-readable representations of the frozen conceptual models. +- [Examples](examples): valid and invalid JSON fixtures. +- [Validator](validator/semantic_validator.py): structural and semantic validation. +- [Passpod SDK](passpod): minimal Python value-object boundary. +- [CLI](passpod/cli.py): local `validate` and `inspect` commands. +- [Tests](tests): unittest coverage for validator, SDK, fixtures, and CLI. -**Sensitive actions should not execute silently.** +Passpod Pilot is the controlled evaluation path for workflow fit, profile candidates, and implementation feedback. Pilot work does not change the Standard unless incorporated into a later revision. -Passpod TASK Core is a public draft standard proposal for **Sensitive Action Control**. -It is the public standard/test layer of the Passpod ecosystem, not the full -Passpod Hub product. +## Repository Map -Every decision returns a **Trust Action Receipt**. +- `docs/STANDARD.md`, `docs/PROTOCOL.md`, `docs/STATE-MODEL.md`, `docs/MESSAGE-MODEL.md`, `docs/PROFILES.md`, `docs/CONFORMANCE.md`: canonical documents. +- `schemas/message.schema.json`, `schemas/handshake.schema.json`, `schemas/profile.schema.json`: current Passpod v0.1 schemas. +- `examples/valid/`: valid message, handshake, and profile fixtures. +- `examples/invalid/`: invalid fixtures used to exercise semantic validation. +- `validator/semantic_validator.py`: validator authority used by the SDK and CLI. +- `passpod/`: minimal Python SDK and CLI module. +- `tests/`: local test suite. +- `docs/QUICKSTART.md`: developer quickstart. -**No receipt, no sensitive action.** +Legacy repository files may remain for historical or migration context. They are not the active Passpod v0.1 architecture. -Public demo receipts in this repository are not production-valid receipts. -Production-valid receipts require authorized issuer access through Passpod Hub and the Pilot Access Engine. +## Quick Example -## Stack position +```json +{ + "handshakeIdentity": "hs-example-001", + "messages": [ + { + "messageIdentity": "msg-propose-001", + "handshakeIdentity": "hs-example-001", + "messageType": "PROPOSE", + "sender": "participant-alpha" + }, + { + "messageIdentity": "msg-challenge-001", + "handshakeIdentity": "hs-example-001", + "parentReference": "msg-propose-001", + "messageType": "CHALLENGE", + "sender": "participant-beta" + }, + { + "messageIdentity": "msg-agree-001", + "handshakeIdentity": "hs-example-001", + "parentReference": "msg-challenge-001", + "messageType": "AGREE", + "sender": "participant-alpha" + }, + { + "messageIdentity": "msg-close-001", + "handshakeIdentity": "hs-example-001", + "parentReference": "msg-agree-001", + "messageType": "CLOSE", + "sender": "participant-beta" + } + ] +} +``` -Passpod TASK Core -> Passpod Hub -> Control Packs -> Pilot Access -> paid pilot / Team / Enterprise. +This is a compact schema-shaped example. It does not define a transport, storage mechanism, signature, identity verification method, or profile implementation. + +## Python SDK + +Use the repository-local package directly from a checkout: + +```python +import json +from pathlib import Path + +from passpod import Handshake, Message, PasspodValidationError, Profile + +mapping = json.loads(Path("examples/valid/complete-handshake.json").read_text()) + +try: + handshake = Handshake.from_mapping(mapping) +except PasspodValidationError as error: + print(error.errors) +else: + print(handshake.lifecycle) + print(handshake.message_count) +``` + +The package root exposes `Message`, `Handshake`, `Profile`, and `PasspodValidationError`. The SDK does not generate identifiers, load files for you, or define transports. -- Passpod TASK Core: public schema, examples, validator, and OpenAPI reference. -- Passpod Hub: paid hosted product layer, not included in this repo. -- Control Packs: AgentTrust and Remote Worker Trust. -- Pilot Access Engine: scoped pilot access path for authorized hosted access. -- DIDX: company, legal, and registry anchor for the ecosystem. +## CLI + +Run the local CLI as a module: + +```bash +python3 -m passpod.cli validate +python3 -m passpod.cli inspect +python3 -m passpod.cli validate --json +python3 -m passpod.cli inspect --json +``` -## Start here +Exit codes: -- [Specification](SPEC.md): public v0.1 TASK Core semantics and boundaries. -- [Trust Action Receipt schema](schemas/trust-action-receipt.schema.json): JSON Schema for public draft receipts. -- [OpenAPI reference](openapi/passpod-task.public.yaml): public reference API shape only. -- [Example receipts](examples/README.md): walkthrough for the demo receipts. -- [Validator](validator/README.md): install and run local receipt validation. -- [Pilot Access](PILOT_ACCESS.md): path for real workflow review and hosted pilot access. -- [Commercial boundary](COMMERCIAL_BOUNDARY.md): what this public repo does and does not expose. +- `0`: command succeeded. +- `1`: recognized artifact is invalid. +- `2`: usage, file, parsing, root-shape, or artifact-detection failure. + +The CLI supports only `validate` and `inspect`. -## Public test vs Pilot Access +## Current Status -Public repo: schema, examples, local validation, public draft. +Passpod Specification v0.1 is conceptually frozen. -Pilot Access: scoped pilot key, hosted receipt endpoint, signed pilot receipts, scenario mapping, security review, and integration support. +The repository currently includes canonical documents, schemas, valid and invalid fixtures, a semantic validator, a minimal Python SDK core, SDK ergonomics, and a local CLI. -Request Pilot Access: pilots@passpod.io +The implementation is minimal and transport-neutral. Production transports, persistence, signatures, cryptography, identity verification, and profile implementations are not included. -## Public/private boundary +## Pilot + +Passpod Pilot is the controlled evaluation path for workflow fit, profile candidates, and implementation feedback. -This repo does not contain production signing keys, scoped key generation internals, buyer-specific workflows, real customer receipts, or Passpod Hub backend code. +Pilot work may produce operational learning, profile candidates, implementation feedback, or conformance questions. It does not redefine the active architecture. +## Legacy Terminology -## Open source maintenance +Previous repository material may refer to archived concepts such as: + +- TASK Core +- TASK Guard +- Passpod Hub +- AgentTrust +- Control Packs +- Pilot Access Engine +- Sensitive Action Control +- Trust Action Receipt as the primary protocol object + +These terms are outside the active Passpod v0.1 architecture. They are preserved as repository history and migration context, not presented as current product modules. + +Historical migration references: + +- [Legacy specification](SPEC.md) +- [Legacy receipt schema](schemas/trust-action-receipt.schema.json) +- [Legacy OpenAPI reference](openapi/passpod-task.public.yaml) +- [Legacy examples guide](examples/README.md) +- [Legacy validator guide](validator/README.md) +- [Legacy pilot access notes](PILOT_ACCESS.md) +- [Legacy commercial boundary notes](COMMERCIAL_BOUNDARY.md) + +Archived legacy wording may include: + +```text +Public demo receipts in this repository are not production-valid receipts. +Production-valid receipts require authorized issuer access through Passpod Hub and the Pilot Access Engine. +Passpod TASK Core -> Passpod Hub -> Control Packs -> Pilot Access -> paid pilot / Team / Enterprise. +``` -Passpod TASK Core is maintained as a public OSS standard layer for sensitive-action control. +Those archived statements describe previous repository positioning. They do not define the active Passpod v0.1 architecture. -- [Roadmap](ROADMAP.md) -- [Funding Use](FUNDING_USE.md) +## License and Contribution -Credits or OSS support requested for this repository are intended for public maintenance only: schema checks, validator/CLI improvements, OpenAPI consistency, examples, tests, documentation, release workflows, and security hardening. +- [License](LICENSE) +- [Contributing](CONTRIBUTING.md) +- [Governance](GOVERNANCE.md) +- [Security](SECURITY.md) +- [Code of Conduct](CODE_OF_CONDUCT.md) diff --git a/docs/QUICKSTART.md b/docs/QUICKSTART.md new file mode 100644 index 0000000..d1c75e6 --- /dev/null +++ b/docs/QUICKSTART.md @@ -0,0 +1,105 @@ +# Passpod Developer Quickstart + +This quickstart helps a developer run the current Passpod v0.1 repository locally. + +## Requirements + +- Python 3 +- Repository checkout +- Standard library interfaces for the Passpod SDK and CLI + +Validation uses the repository validator dependency declared in [requirements.txt](../requirements.txt). + +## Run All Tests + +From the repository root: + +```bash +PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests +``` + +## Validate Fixtures + +Validate a known-good handshake fixture: + +```bash +python3 -m passpod.cli validate examples/valid/complete-handshake.json +``` + +Validate a known-invalid handshake fixture: + +```bash +python3 -m passpod.cli validate examples/invalid/missing-parent.json +``` + +Exit-code behavior: + +- `0`: command succeeded. +- `1`: recognized artifact is invalid. +- `2`: usage, file, parsing, root-shape, or artifact-detection failure. + +Machine-readable output is available with `--json`: + +```bash +python3 -m passpod.cli validate examples/valid/complete-handshake.json --json +``` + +## Inspect A Handshake + +Inspect a bounded handshake summary: + +```bash +python3 -m passpod.cli inspect examples/valid/complete-handshake.json +``` + +Inspect the same artifact as JSON: + +```bash +python3 -m passpod.cli inspect examples/valid/complete-handshake.json --json +``` + +Inspection prints only a bounded summary. It does not print full message payloads, evidence payloads, extension payloads, or complete participant payloads. + +## SDK Example + +```python +import json +from pathlib import Path + +from passpod import Handshake + +path = Path("examples/valid/complete-handshake.json") +mapping = json.loads(path.read_text(encoding="utf-8")) + +handshake = Handshake.from_mapping(mapping) + +print(handshake.lifecycle) +print(handshake.message_count) + +round_tripped = handshake.to_mapping() +``` + +SDK objects accept mappings. File loading stays with Python's standard library. + +## Validation Layers + +Passpod validation proceeds through these layers: + +1. JSON parsing. +2. Structural schema validation. +3. Semantic protocol validation. +4. SDK value-object boundary. + +The Passpod Standard and Handshake Protocol remain the source of protocol semantics. The schemas, validator, SDK, and CLI consume those semantics; they do not replace them. + +## Unsupported Behavior + +The current repository does not include: + +- network transport; +- HTTP API; +- persistence; +- signatures or cryptography; +- identity verification; +- reference profile implementation; +- legacy TASK behavior. From af39a108543e543f0fb8d365902c6fd5823dd4a7 Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 03:18:43 +0800 Subject: [PATCH 05/18] Map canonical repository and legacy migration --- docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md | 441 +++++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md diff --git a/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md b/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md new file mode 100644 index 0000000..9cffa20 --- /dev/null +++ b/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md @@ -0,0 +1,441 @@ +# Canonical Repository Migration Map + +## 1. Executive Summary + +This audit reviewed every tracked repository asset after the Passpod v0.1 reset. + +Baseline commands were clean: + +```text +git status --short +``` + +returned no output, and: + +```text +git log -5 --oneline +``` + +showed: + +```text +35699ea Migrate README and quickstart to Passpod v0.1 +3118802 Add minimal Passpod validate and inspect CLI +96d15ee Refine SDK ergonomics and fixture round trips +d42ce39 Freeze Passpod v0.1 specification and add SDK core +fc8e2aa Document OSS funding use and roadmap (#15) +``` + +The active Passpod v0.1 architecture is now present and usable: + +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` + +Canonical documents, schemas, valid and invalid fixtures, the semantic validator, SDK, CLI, README, and quickstart are in place. The main cleanup risk is that the repository still contains tracked TASK-era documentation, receipt schemas, receipt examples, OpenAPI material, and a public gate that requires legacy terminology and legacy links. Cleanup must therefore start by migrating the gate and CI expectations before archiving or moving old files. + +Classification counts across the 74 tracked assets audited: + +| Classification | Count | +|---|---:| +| KEEP - Canonical | 33 | +| KEEP - Supporting | 7 | +| MIGRATE | 25 | +| ARCHIVE | 7 | +| DELETE-CANDIDATE | 0 | +| DEFER | 2 | + +No cleanup, deletion, rename, move, archive, code change, documentation rewrite, commit, or push was performed in this pass. This document is the only created file. + +## 2. Audit Scope + +The audit covered all tracked files from `git ls-files`, including: + +- root-level public, governance, launch, adoption, roadmap, versioning, and security files; +- `.github` ownership, pull request, and workflow files; +- all files under `docs/`; +- all schema files under `schemas/`; +- all examples under `examples/`; +- all SDK, validator, CLI, and tool code; +- all tests; +- OpenAPI and worker-reference material. + +The audit used the current canonical documents and implementation as source of truth. Older README, SPEC, OpenAPI, receipt examples, receipt schema, receipt validator behavior, and historical docs were treated as tracked evidence, not as canonical architecture. + +The active architecture does not center TASK, execution control, Trust Action Receipts, Passpod Hub, AgentTrust, Control Packs, Pilot Access Engine, Kill-State, receipt decision states, or receipt issuance. + +## 3. Canonical Baseline + +Canonical active assets: + +- `README.md` +- `docs/STANDARD.md` +- `docs/PROTOCOL.md` +- `docs/STATE-MODEL.md` +- `docs/MESSAGE-MODEL.md` +- `docs/PROFILES.md` +- `docs/CONFORMANCE.md` +- `docs/TERMINOLOGY.md` +- `docs/QUICKSTART.md` +- `schemas/message.schema.json` +- `schemas/handshake.schema.json` +- `schemas/profile.schema.json` +- `examples/valid/*.json` +- `examples/invalid/*.json` +- `validator/semantic_validator.py` +- `passpod/*.py` +- `tests/test_semantic_validator.py` +- `tests/test_sdk_core.py` +- `tests/test_sdk_fixture_roundtrip.py` +- `tests/test_cli.py` + +Supporting canonical evidence: + +- `docs/SPECIFICATION_FREEZE_REPORT.md` + +Important active boundaries: + +- Passpod is transport-neutral. +- A handshake is append-only. +- Accepted messages are immutable. +- `CLOSE` ends active negotiation. +- Profiles specialize Passpod without redefining the core protocol. +- The SDK and CLI consume the validator and schemas; they do not redefine the Standard. + +## 4. Classification Criteria + +| Classification | Meaning used in this audit | +|---|---| +| KEEP - Canonical | The asset is part of active Passpod v0.1 and should remain substantially as-is. | +| KEEP - Supporting | The asset remains useful as governance, legal, dependency, audit, or other supplementary material but is not normative architecture. | +| MIGRATE | The asset contains reusable material but still reflects legacy architecture, terminology, structure, or behavior. | +| ARCHIVE | The asset should remain accessible for history or migration context but should not remain in the active developer path. | +| DELETE-CANDIDATE | The tracked asset appears redundant, obsolete, generated, contaminated beyond useful migration value, or superseded. No tracked asset met this bar with enough dependency evidence. | +| DEFER | Treatment depends on a later product, governance, packaging, release, legal, public-surface, or transport-binding decision. | + +For MIGRATE, ARCHIVE, and DEFER assets, dependencies were checked through content inspection, path-reference search, imports, tests, CI workflow configuration, README links, and tool consumers. + +## 5. Root-Level Asset Map + +| Path | Classification | Reason | Dependencies | Proposed future action | +|---|---|---|---|---| +| `README.md` | KEEP - Canonical | Active public entry point for Passpod v0.1 with legacy wording explicitly quarantined. | Links to canonical docs and legacy references required by current gate. | Keep active; remove legacy migration block only after gate migration. | +| `SPEC.md` | ARCHIVE | Legacy TASK Core specification centered on Trust Action Receipt and decision states. | Linked by README legacy section; required by `tools/check-public-task-repo.sh`. | Move conceptually to `archive/legacy-task/` after gate no longer requires it. | +| `ADOPTION.md` | MIGRATE | Reader paths are useful, but active wording is TASK Core, Sensitive Action Control, Hub, and Pilot Access Engine. | Required by current gate for legacy phrases. | Rewrite later for Standard, SDK, validator, and Passpod Pilot audiences. | +| `CHANGELOG.md` | KEEP - Supporting | Minimal release history. Does not define active architecture. | No inbound runtime or gate dependency found. | Keep; expand later with Passpod v0.1 release notes if release policy is defined. | +| `CODE_OF_CONDUCT.md` | KEEP - Supporting | Generic community policy. | No active code dependency. | Keep. | +| `COMMERCIAL_BOUNDARY.md` | MIGRATE | Boundary concept is useful, but product stack is TASK Core, Hub, Control Packs, Pilot Access. | README legacy links; current gate requires exact legacy distinctions. | Rewrite after gate migration for Passpod Pilot and commercial boundary. | +| `CONTRIBUTING.md` | MIGRATE | Public safety guidance is useful, but contribution categories still mention receipt examples and scoped-key internals. | Required file in current gate. | Retain safety policy; update terminology after gate migration. | +| `FUNDING_USE.md` | MIGRATE | Funding narrative still centers TASK Core, receipt gallery, and decision states. | README links were removed from active map but file remains public. | Rewrite only with public-funding strategy approval. | +| `GOVERNANCE.md` | MIGRATE | Governance is needed, but current text says TASK Core is stewarded by DIDX. | Required file in current gate. | Confirm stewardship language, then migrate to Passpod v0.1. | +| `LAUNCH_READINESS.md` | MIGRATE | Launch checklist encodes old public TASK and Pilot Access assumptions. | Current gate searches this file for legacy product terms. | Convert into Passpod v0.1 readiness checklist after gate migration. | +| `LICENSE` | KEEP - Supporting | MIT license and copyright notice. | OpenAPI license metadata references repository license. | Keep; legal changes require explicit approval. | +| `PILOT_ACCESS.md` | MIGRATE | Pilot funnel concept is relevant but uses Hub and Pilot Access Engine. | README legacy link; current gate checks `pilots@passpod.io`. | Rewrite as Passpod Pilot workflow-fit evaluation after gate migration. | +| `ROADMAP.md` | MIGRATE | Roadmap is old receipt/TASK roadmap. | Public file, not test-consumed. | Replace with Passpod v0.1 roadmap only after strategy approval. | +| `SECURITY.md` | KEEP - Supporting | Minimal security contact. | Current gate checks `pilots@passpod.io` here. | Keep; later confirm whether security contact should remain this mailbox. | +| `VERSIONING.md` | MIGRATE | Version ladder is for stable receipt core, not Standard/Protocol/Profile/SDK versioning. | Required file in current gate. | Rewrite after version policy is defined. | +| `requirements.txt` | KEEP - Supporting | Declares `jsonschema[format]>=4,<5`, used by validator and tests. | CI installs it; validator imports `jsonschema`. | Keep until validation dependency strategy changes. | + +## 6. Documentation Map + +| Path | Classification | Reason | Dependencies | Proposed future action | +|---|---|---|---|---| +| `docs/STANDARD.md` | KEEP - Canonical | Normative semantic authority. | Linked by README; source for architecture. | Keep. | +| `docs/PROTOCOL.md` | KEEP - Canonical | Defines canonical transport-neutral handshake flow. | Linked by README; source for validator/SDK semantics. | Keep. | +| `docs/STATE-MODEL.md` | KEEP - Canonical | Defines conceptual message and handshake lifecycle. | Linked by README; reflected by schemas and SDK lifecycle helpers. | Keep. | +| `docs/MESSAGE-MODEL.md` | KEEP - Canonical | Defines conceptual message structure. | Linked by README; represented by message schema and SDK. | Keep. | +| `docs/PROFILES.md` | KEEP - Canonical | Defines profile model and profile boundaries. | Linked by README; represented by profile schema. | Keep. | +| `docs/CONFORMANCE.md` | KEEP - Canonical | Defines conformance philosophy and layer alignment. | Linked by README. | Keep. | +| `docs/TERMINOLOGY.md` | KEEP - Canonical | Normatively defines active terms and labels legacy terms as archived. | Linked by README; source for terminology migration. | Keep. | +| `docs/QUICKSTART.md` | KEEP - Canonical | Active developer quickstart. | Linked by README; commands match current CLI/tests. | Keep. | +| `docs/SPECIFICATION_FREEZE_REPORT.md` | KEEP - Supporting | Historical audit supporting the frozen v0.1 specification. | Linked by README; no runtime consumers. | Keep in docs for now; optional future move to release audit archive. | +| `docs/PASSPOD-RESET-AUDIT.md` | ARCHIVE | Pre-freeze reset audit, now superseded by canonical docs and this map. | Self-references old state; no runtime consumers. | Move conceptually to `docs/archive/` or `archive/legacy-task/` after archive policy exists. | +| `docs/glossary.md` | MIGRATE | Legacy glossary presents TASK Core, Hub, AgentTrust, Control Packs, and Pilot Access Engine as active. | Required by current gate. | Replace with or redirect to `docs/TERMINOLOGY.md` after gate migration. | +| `docs/non-goals.md` | MIGRATE | Useful boundary shape but active subject is TASK. | No direct consumers found. | Migrate useful boundary ideas into canonical non-goals if needed. | +| `docs/production-checklist.md` | MIGRATE | Checklist centers TASK, signatures, storage, verification, freeze, and revoke. | Required by current gate. | Rewrite for implementation readiness only after gate migration. | +| `docs/public-vs-pilot.md` | MIGRATE | Useful public/pilot distinction, but old scoped keys and hosted endpoint framing. | Required by current gate. | Rewrite for public Standard/SDK versus Passpod Pilot. | +| `docs/receipt-lifecycle.md` | ARCHIVE | Legacy lifecycle conflicts with active handshake lifecycle. | No direct consumers found. | Archive as receipt-era documentation after gate and docs cleanup. | +| `docs/security-model.md` | MIGRATE | Security boundary is useful, but old TASK receipt/signing model is active. | No direct consumers found. | Rewrite around handshake, evidence, profiles, and implementation boundaries. | +| `docs/standardization-roadmap.md` | MIGRATE | Public feedback and compatibility idea is useful, but roadmap is receipt-core oriented. | Required by current gate. | Rewrite after roadmap decision. | +| `docs/threat-model.md` | MIGRATE | Threat topics are reusable, but receipt/control framing should be updated. | No direct consumers found. | Migrate into active security/threat model later. | + +## 7. Schema Map + +| Path | Classification | Reason | Dependencies | Proposed future action | +|---|---|---|---|---| +| `schemas/message.schema.json` | KEEP - Canonical | Canonical machine-readable message model. | Loaded by `validator/semantic_validator.py`; covered by tests. | Keep. | +| `schemas/handshake.schema.json` | KEEP - Canonical | Canonical machine-readable handshake model. | Loaded by validator; references message schema; covered by tests. | Keep. | +| `schemas/profile.schema.json` | KEEP - Canonical | Canonical machine-readable profile model. | Loaded by validator; covered by tests. | Keep. | +| `schemas/trust-action-receipt.schema.json` | ARCHIVE | Legacy receipt/TASK schema with decision enum `allow`, `deny`, `review_required`, `freeze`, `revoke`. | README legacy link, SPEC, OpenAPI, `tools/validate-receipts.py`, CI, current gate, validator README. | Do not delete. Archive only after gate, CI, legacy examples, and receipt validator are migrated or retired. | + +Schema dependency notes: + +- The canonical validator uses the three Passpod v0.1 schemas. +- The legacy receipt validator uses only `schemas/trust-action-receipt.schema.json`. +- The current CI workflow JSON-checks only the legacy receipt schema and three legacy receipt examples before running the legacy gate. +- No `$ref` dependency from canonical schemas points to the legacy receipt schema. + +## 8. Examples and Fixtures Map + +| Path | Classification | Reason | Dependencies | Proposed future action | +|---|---|---|---|---| +| `examples/valid/complete-handshake.json` | KEEP - Canonical | Valid complete `PROPOSE -> CHALLENGE -> AGREE -> CLOSE` fixture. | Validator, SDK round-trip tests, CLI tests. | Keep. | +| `examples/valid/minimal-profile.json` | KEEP - Canonical | Valid minimal profile fixture. | Validator, SDK, CLI tests. | Keep. | +| `examples/valid/minimal-propose.json` | KEEP - Canonical | Valid standalone message fixture. | Validator, SDK, CLI tests. | Keep. | +| `examples/valid/propose-challenge-agree.json` | KEEP - Canonical | Valid partial handshake fixture. | Validator and SDK round-trip tests. | Keep. | +| `examples/valid/propose-challenge.json` | KEEP - Canonical | Valid challenge-stage handshake fixture. | Validator and SDK round-trip tests. | Keep. | +| `examples/invalid/close-before-agree.json` | KEEP - Canonical | Invalid canonical fixture for terminal closure before agreement. | Validator, SDK round-trip, CLI tests. | Keep. | +| `examples/invalid/duplicate-message-id.json` | KEEP - Canonical | Invalid canonical fixture for duplicate message identity. | Validator, SDK round-trip, CLI tests. | Keep. | +| `examples/invalid/invalid-transition.json` | KEEP - Canonical | Invalid canonical fixture for bad message transition. | Validator, SDK round-trip, CLI tests. | Keep. | +| `examples/invalid/missing-parent.json` | KEEP - Canonical | Invalid canonical fixture for missing parent reference. | Validator, SDK round-trip, CLI tests; quickstart uses it. | Keep. | +| `examples/invalid/redefine-message-type.json` | KEEP - Canonical | Invalid canonical fixture for profile redefinition. | Validator, SDK round-trip, CLI tests. | Keep. | +| `examples/README.md` | MIGRATE | Walkthrough for legacy receipt examples. | README legacy link; current gate; legacy validator docs. | Rewrite after legacy receipt examples are archived or reframed. | +| `examples/remote-worker.receipt.json` | MIGRATE | Legacy receipt scenario that may inform a future profile candidate. | CI JSON check, legacy validator, examples README, current gate, pilot-readiness usage. | Preserve until replacement exists; do not promote as active profile without profile governance. | +| `examples/refund-review.receipt.json` | MIGRATE | Legacy receipt scenario that may inform future workflow examples. | CI JSON check, legacy validator, examples README. | Preserve until replacement exists; migrate scenario only if useful. | +| `examples/agent-freeze.receipt.json` | ARCHIVE | Legacy AgentTrust/Kill-State receipt example; tightly coupled to execution freeze. | CI JSON check, legacy validator, examples README. | Archive after CI/gate no longer require it. | + +## 9. Validator, SDK, and CLI Map + +| Path | Classification | Reason | Dependencies | Proposed future action | +|---|---|---|---|---| +| `validator/semantic_validator.py` | KEEP - Canonical | Active structural and semantic validator for message, handshake, and profile artifacts. | Imports `jsonschema`; reads canonical schemas; used by SDK and tests. | Keep. | +| `passpod/__init__.py` | KEEP - Canonical | Public package-root imports. | Used by tests and CLI. | Keep. | +| `passpod/errors.py` | KEEP - Canonical | SDK validation exception boundary. | Used by SDK classes and CLI. | Keep. | +| `passpod/message.py` | KEEP - Canonical | Message value object. | Uses canonical validator; covered by tests. | Keep. | +| `passpod/handshake.py` | KEEP - Canonical | Handshake value object and read-only conveniences. | Uses Message and canonical validator; covered by tests. | Keep. | +| `passpod/profile.py` | KEEP - Canonical | Profile value object. | Uses canonical validator; covered by tests. | Keep. | +| `passpod/cli.py` | KEEP - Canonical | Active local `validate` and `inspect` CLI. | Uses package-root SDK imports; covered by subprocess tests. | Keep. | +| `validator/README.md` | MIGRATE | Documents legacy receipt validator, not active semantic validator. | README legacy link; current gate; links to `tools/validate-receipts.py`. | Rewrite to document `validator/semantic_validator.py` after gate migration. | +| `cli/README.md` | MIGRATE | Says no standalone CLI exists, contradicting active `python3 -m passpod.cli`. | README legacy link; current gate; links to legacy receipt validator. | Rewrite or replace with pointer to `docs/QUICKSTART.md` after gate migration. | +| `tools/validate-receipts.py` | MIGRATE | Legacy receipt validator with useful public-safety checks. | Current gate, CI, examples README, validator README, cli README. | Migrate reusable safety checks into a v0.1 gate, then archive receipt-specific logic. | +| `tools/pilot-readiness.py` | DEFER | Legacy receipt readiness scoring helper. | No CI dependency; usage references `examples/remote-worker.receipt.json`. | Defer until Passpod Pilot assessment model is defined. | + +Import notes: + +- Active SDK modules import `validator.semantic_validator`. +- Active CLI imports package-root `Handshake`, `Message`, `Profile`, and `PasspodValidationError`. +- Legacy `tools/validate-receipts.py` imports `jsonschema` and does not participate in the active SDK/CLI path. + +## 10. OpenAPI and Transport Material Map + +| Path | Classification | Reason | Dependencies | Proposed future action | +|---|---|---|---|---| +| `openapi/passpod-task.public.yaml` | ARCHIVE | Legacy receipt API shape for `/v1/spec`, `/v1/receipts/validate`, and `/v1/receipts/{receipt_id}`. Passpod v0.1 core is transport-neutral. | README legacy link, openapi README, current gate. | Archive after gate migration unless a separate transport-binding pass explicitly supersedes it. | +| `openapi/README.md` | ARCHIVE | Documents legacy receipt OpenAPI reference and Hub/Pilot Access Engine boundary. | README legacy link; current gate. | Archive with OpenAPI YAML after gate migration. | +| `worker-reference/README.md` | DEFER | Reserved future Worker material tied to legacy receipt validation. | README legacy link; current gate. | Defer until transport/reference implementation scope is decided. | + +Transport conclusion: + +- No OpenAPI file is part of the active core protocol. +- Any future OpenAPI should be treated as a separate transport binding, not as the Standard or Handshake Protocol. +- The current OpenAPI material describes obsolete receipt endpoints and should not remain on the active developer path after the gate is migrated. + +## 11. Tests, CI, and Tooling Map + +| Path | Classification | Reason | Dependencies | Proposed future action | +|---|---|---|---|---| +| `tests/test_semantic_validator.py` | KEEP - Canonical | Tests canonical validator and canonical fixtures. | Imports validator by file path; reads `examples/valid` and `examples/invalid`. | Keep. | +| `tests/test_sdk_core.py` | KEEP - Canonical | Tests SDK value objects and validation boundary. | Imports package root. | Keep. | +| `tests/test_sdk_fixture_roundtrip.py` | KEEP - Canonical | Tests canonical fixtures through SDK and validator. | Reads canonical fixtures; imports SDK and validator. | Keep. | +| `tests/test_cli.py` | KEEP - Canonical | Tests active module CLI through subprocess. | Runs `python3 -m passpod.cli`; reads canonical fixtures. | Keep. | +| `.github/CODEOWNERS` | KEEP - Supporting | GitHub review ownership. | GitHub platform behavior. | Keep unless ownership changes. | +| `.github/PULL_REQUEST_TEMPLATE.md` | MIGRATE | Checklist is TASK-era but private-data checks remain useful. | Mentions `tools/check-public-task-repo.sh`. | Update after gate migration. | +| `.github/workflows/validate.yml` | MIGRATE | CI validates legacy receipt schema/examples and runs legacy public gate. | Installs `requirements.txt`, JSON-checks legacy files, runs `tools/check-public-task-repo.sh`. | Retarget after gate migration. | +| `tools/check-public-task-repo.sh` | MIGRATE | Existing gate protects some public/private boundaries but enforces obsolete TASK-era architecture. | Called by CI and PR template; reads many legacy docs and `tools/validate-receipts.py`. | First cleanup dependency to migrate. Preserve secret/private-data scanning and JSON safety checks where useful. | + +Legacy gate findings: + +- Useful checks to preserve: required public files, JSON validity, public/private leakage scans, secret-key marker scans, no placeholder-only README checks, and sanitized-example discipline. +- Obsolete checks: requiring TASK Core, Sensitive Action Control, Trust Action Receipt as primary object, Passpod Hub, Control Packs, AgentTrust, Pilot Access Engine, old product stack, old README launch navigation, old receipt schema, and old receipt examples. +- Cleanup blocker: archiving `SPEC.md`, legacy OpenAPI, legacy examples, legacy schema, or old README links will break this gate until it is migrated. + +## 12. Legacy Terminology Reference Map + +Repository-wide search before this report found these legacy/reference counts: + +| Term | Hits | Files | Treatment | +|---|---:|---:|---| +| `TASK` | 101 | 26 | Active contamination except in canonical archived-terminology sections and migration docs. | +| `TASK Core` | 48 | 17 | Legacy architecture; should remain only in archive/migration context. | +| `TASK Guard` | 7 | 4 | Already archived terminology in canonical docs or reset audit context. | +| `Trust Action Receipt` | 28 | 18 | Legacy primary object; not active v0.1 protocol object. | +| `Passpod Hub` | 41 | 17 | Legacy hosted product concept; should be archived or migrated out of active path. | +| `AgentTrust` | 22 | 10 | Legacy Control Pack concept; possible scenario evidence only. | +| `Control Packs` | 20 | 8 | Legacy architecture. | +| `Pilot Access Engine` | 36 | 15 | Legacy pilot access implementation concept; superseded by Passpod Pilot framing. | +| `Sensitive Action Control` | 22 | 11 | Legacy category. | +| `Kill-State` | 8 | 4 | Legacy execution-freeze concept, primarily archive material. | +| `allow` | 27 | 13 | Mostly legacy receipt decision state; generic uses must be reviewed in context. | +| `deny` | 9 | 5 | Legacy receipt decision state. | +| `freeze` | 35 | 11 | Legacy receipt/execution-control state. | +| `revoke` | 12 | 6 | Legacy receipt decision state. | +| `receipt` | 223 | 30 | Mostly legacy receipt-era architecture and examples. | +| `issue` | 45 | 22 | Mixed generic language and legacy receipt/production boundary language. | +| `verify` | 0 | 0 | Exact word not found; `verification` appears in legacy and generic security contexts. | + +Context distinctions: + +- Explicitly archived historical mentions: `docs/TERMINOLOGY.md`, `docs/SPECIFICATION_FREEZE_REPORT.md`, README legacy section, and reset audit material. +- Active legacy architecture: `SPEC.md`, `ADOPTION.md`, `COMMERCIAL_BOUNDARY.md`, `PILOT_ACCESS.md`, `docs/glossary.md`, `examples/README.md`, OpenAPI material, validator README, CLI README, worker reference README, legacy receipt schema, and legacy gate. +- Legitimate generic usage: "evidence", "issue" as ordinary documentation language, "verification" in security notes, and "allow" when used outside the receipt decision enum. +- Implementation dependencies: legacy gate and CI require legacy schema/examples/docs; active SDK/CLI/tests do not. +- False positives: canonical docs use "allow" as English or "verification" as a non-prescribed trust mechanic; those are not contamination by themselves. + +## 13. Dependency Risks + +| Risk | Affected assets | Why it matters | Required predecessor action | +|---|---|---|---| +| Legacy gate enforces obsolete architecture | `tools/check-public-task-repo.sh`, CI, README legacy links, `SPEC.md`, old docs, old schema, old examples | Cleanup will fail CI if files or strings are moved before the gate changes. | Migrate gate first. | +| CI validates old receipt assets | `.github/workflows/validate.yml`, `schemas/trust-action-receipt.schema.json`, `examples/*.receipt.json` | Removing old examples or schema breaks workflow. | Retarget CI to canonical schemas, fixtures, tests, and v0.1 gate. | +| README retains legacy block for gate compatibility | `README.md`, `tools/check-public-task-repo.sh` | Active public README contains quarantined legacy text only because the gate requires it. | Replace gate checks, then remove legacy block in a later doc pass. | +| Legacy docs have active public-surface links | `README.md`, `SPEC.md`, OpenAPI, examples README, validator README, CLI README, commercial boundary | Archiving too early causes dead links and gate failures. | Produce link rewrite plan after gate migration. | +| Legacy receipt validator contains useful safety checks | `tools/validate-receipts.py`, `tools/check-public-task-repo.sh` | Deleting it would lose secret/private-data marker scanning until replacement exists. | Port safety checks to canonical gate before archiving. | +| Pilot wording mixes useful funnel concepts with obsolete engine language | `PILOT_ACCESS.md`, `SECURITY.md`, `tools/pilot-readiness.py`, commercial docs | Human business/security decisions are needed before rewriting. | Confirm Passpod Pilot and contact policy. | +| OpenAPI may be mistaken for active protocol | `openapi/passpod-task.public.yaml`, `openapi/README.md` | Passpod v0.1 is transport-neutral; old routes are receipt-specific. | Archive old OpenAPI or replace only in a future transport-binding pass. | + +Detailed dependency map for highest-risk noncanonical assets: + +| Asset | Current purpose | Inbound references | Outbound references/imports | Test/CI/tool consumers | README links | Migration risk | Recommended action | Predecessor actions | +|---|---|---|---|---|---|---|---|---| +| `tools/check-public-task-repo.sh` | Legacy public repo gate. | CI workflow, PR template. | Reads README, SPEC, legacy docs, old schema, old examples; calls `tools/validate-receipts.py`. | Direct CI consumer. | Indirectly protects legacy README links. | Very high. | Migrate to Passpod v0.1 gate. | None; this is first. | +| `.github/workflows/validate.yml` | Runs legacy JSON checks and gate. | GitHub Actions. | `requirements.txt`, old schema, old examples, gate. | CI. | README badge indirectly points at workflow path. | High. | Retarget after gate exists. | Gate migration. | +| `schemas/trust-action-receipt.schema.json` | Legacy receipt schema. | README legacy link, SPEC, OpenAPI, gate, validator. | None beyond JSON Schema draft. | CI and legacy validator. | Yes. | High. | Archive after replacement checks. | Gate and CI migration. | +| `examples/*.receipt.json` | Legacy sanitized receipt examples. | CI, legacy validator, examples README, gate. | Old schema fields. | CI and `tools/validate-receipts.py`. | README links examples README. | High. | Migrate or archive by scenario. | Gate and CI migration. | +| `SPEC.md` | Legacy TASK Core spec. | README legacy link, gate. | Old schema, examples, Pilot Access. | Gate. | Yes. | High. | Archive as legacy specification. | Gate and README link migration. | +| `openapi/passpod-task.public.yaml` | Legacy receipt API reference. | README legacy link, openapi README, gate. | Old schema URL and receipt route models. | Gate requires file exists. | Yes. | Medium-high. | Archive unless future transport binding is approved. | Gate and README link migration. | +| `tools/validate-receipts.py` | Legacy receipt validator. | Gate, examples README, validator README, cli README. | Old schema, `examples/*.receipt.json`, `jsonschema`. | Gate. | Indirect. | High. | Port safety checks, then archive. | Gate migration. | + +## 14. Canonical Destination Structure + +Conceptual target shape after cleanup: + +```text +README.md +docs/ + STANDARD.md + PROTOCOL.md + STATE-MODEL.md + MESSAGE-MODEL.md + PROFILES.md + CONFORMANCE.md + TERMINOLOGY.md + QUICKSTART.md + SPECIFICATION_FREEZE_REPORT.md + archive/ +schemas/ + message.schema.json + handshake.schema.json + profile.schema.json +examples/ + valid/ + invalid/ +validator/ + semantic_validator.py +passpod/ + __init__.py + cli.py + errors.py + message.py + handshake.py + profile.py +tests/ + test_semantic_validator.py + test_sdk_core.py + test_sdk_fixture_roundtrip.py + test_cli.py +tools/ + passpod-v0.1-gate.sh +archive/ + legacy-task/ + SPEC.md + schemas/ + examples/ + openapi/ + docs/ +``` + +Destination principles: + +- Normative specification remains in `docs/`. +- Developer documentation remains in README and `docs/QUICKSTART.md`. +- Canonical fixtures remain in `examples/valid/` and `examples/invalid/`. +- Active implementations remain in `validator/`, `passpod/`, and `tests/`. +- Alternative implementations should only appear after they have a defined active purpose. +- Transport bindings should live outside the core protocol and be labeled as bindings. +- Historical legacy material should move to `archive/legacy-task/` or `docs/archive/` with links rewritten after the gate allows it. + +## 15. Recommended Cleanup Sequence + +1. Canonical gate migration from TASK-era checks to Passpod v0.1 checks. + + Scope: replace legacy assertions in `tools/check-public-task-repo.sh` with checks for canonical docs, canonical schemas, canonical fixtures, SDK/CLI tests, secret/private-data scanning, and archived-terminology containment. + + Stop/go gate: `python3 -m unittest discover -s tests`, migrated gate, `git diff --check`, and CI-local equivalent must pass. + +2. CI workflow migration. + + Scope: update `.github/workflows/validate.yml` to run the canonical gate and canonical test suite instead of old receipt-only JSON checks. + + Stop/go gate: GitHub workflow and local commands must pass without referencing old receipt examples as active. + +3. Public link migration. + + Scope: remove README legacy compatibility block, point public docs to canonical v0.1 docs, and make old links explicitly archival. + + Stop/go gate: link audit confirms no dead relative links and legacy terms appear only in archive/migration sections. + +4. Legacy schema and receipt example archive plan. + + Scope: move old receipt schema, old receipt examples, old examples README, and old receipt validator documentation conceptually into archive. Do not delete until references are fully rewritten. + + Stop/go gate: canonical tests and gate pass without `schemas/trust-action-receipt.schema.json` or `examples/*.receipt.json` on the active path. + +5. OpenAPI and transport decision. + + Scope: either archive old OpenAPI material or create a separate future transport-binding plan. Do not make OpenAPI part of the core protocol. + + Stop/go gate: README and docs clearly distinguish transport binding from Standard and Protocol. + +6. Legacy root documentation migration. + + Scope: migrate or archive `ADOPTION.md`, `COMMERCIAL_BOUNDARY.md`, `PILOT_ACCESS.md`, `ROADMAP.md`, `VERSIONING.md`, `FUNDING_USE.md`, `LAUNCH_READINESS.md`, and governance/contribution wording. + + Stop/go gate: human review for commercial, governance, security, and roadmap claims. + +7. Documentation archive consolidation. + + Scope: move reset audit, legacy glossary, legacy receipt lifecycle, legacy security and production docs into the chosen archive structure. + + Stop/go gate: active docs tree contains only canonical docs, active guidance, and clearly current support docs. + +## 16. Explicit Non-actions + +This pass did not: + +- modify existing files; +- delete files; +- move files; +- rename files; +- archive files; +- rewrite links; +- change tests; +- change the gate; +- update CI; +- update package metadata; +- change active implementation; +- create cleanup scripts; +- create schemas; +- create examples; +- create code; +- commit; +- push. + +No tracked asset is recommended as a deletion candidate until dependencies are migrated and human review confirms historical value is no longer needed. + +## 17. Final Recommendation + +Recommended next bounded pass: + +Canonical gate migration from TASK-era checks to Passpod v0.1 checks + +Do not begin cleanup, archiving, CI rewrites, link rewrites, OpenAPI changes, or legacy-file moves until that gate migration is complete and passing. From 1efb41bfcc6074bfba878bf9823c4e81c9faa77a Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 03:24:44 +0800 Subject: [PATCH 06/18] Migrate public repository gate to Passpod v0.1 --- tools/check-public-task-repo.sh | 289 +++++++++++++++++++++++++------- 1 file changed, 229 insertions(+), 60 deletions(-) diff --git a/tools/check-public-task-repo.sh b/tools/check-public-task-repo.sh index c3dd74e..15be96f 100755 --- a/tools/check-public-task-repo.sh +++ b/tools/check-public-task-repo.sh @@ -1,74 +1,243 @@ #!/usr/bin/env bash set -euo pipefail -fail() { echo "❌ $1" >&2; exit 1; } -required_files=(README.md SPEC.md PILOT_ACCESS.md ADOPTION.md SECURITY.md CONTRIBUTING.md GOVERNANCE.md VERSIONING.md COMMERCIAL_BOUNDARY.md requirements.txt schemas/trust-action-receipt.schema.json examples/remote-worker.receipt.json examples/README.md openapi/passpod-task.public.yaml openapi/README.md validator/README.md cli/README.md worker-reference/README.md docs/glossary.md docs/public-vs-pilot.md docs/production-checklist.md docs/standardization-roadmap.md tools/validate-receipts.py) +fail() { + echo "ERROR: $1" >&2 + exit 1 +} -for f in "${required_files[@]}"; do - [ -f "$f" ] || fail "Missing required file: $f" -done +require_file() { + local path="$1" + [ -f "$path" ] || fail "Missing required file: $path; expected canonical Passpod v0.1 repository asset" +} -find openapi -type f | grep -q . || fail "openapi/ must contain a public reference draft" - -grep -R "No receipt, no sensitive action" README.md SPEC.md >/dev/null || fail "Canonical doctrine missing" -grep -R "Sensitive Action Control" README.md SPEC.md ADOPTION.md >/dev/null || fail "Sensitive Action Control category missing" -grep -R "public draft standard proposal" README.md SPEC.md ADOPTION.md >/dev/null || fail "Public draft standard proposal wording missing" -grep -R "pilots@passpod.io" README.md PILOT_ACCESS.md SECURITY.md >/dev/null || fail "Pilot Access email missing" - -for link in \ - "SPEC.md" \ - "schemas/trust-action-receipt.schema.json" \ - "openapi/passpod-task.public.yaml" \ - "examples/README.md" \ - "validator/README.md" \ - "PILOT_ACCESS.md" \ - "COMMERCIAL_BOUNDARY.md" -do - grep -q "$link" README.md || fail "README missing launch navigation link: $link" -done +require_dir() { + local path="$1" + [ -d "$path" ] || fail "Missing required directory: $path; expected canonical Passpod v0.1 repository asset" +} + +require_contains() { + local path="$1" + local needle="$2" + local expectation="$3" + + grep -Fq "$needle" "$path" || fail "$path failed check; expected $expectation" +} + +require_json() { + local path="$1" + PYTHONDONTWRITEBYTECODE=1 python3 -m json.tool "$path" >/dev/null \ + || fail "$path failed JSON parsing; expected valid JSON" +} + +canonical_files=( + README.md + docs/STANDARD.md + docs/PROTOCOL.md + docs/STATE-MODEL.md + docs/MESSAGE-MODEL.md + docs/PROFILES.md + docs/CONFORMANCE.md + docs/TERMINOLOGY.md + docs/SPECIFICATION_FREEZE_REPORT.md + docs/QUICKSTART.md + docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md + schemas/message.schema.json + schemas/handshake.schema.json + schemas/profile.schema.json + validator/semantic_validator.py + passpod/__init__.py + passpod/cli.py + passpod/message.py + passpod/handshake.py + passpod/profile.py + passpod/errors.py + tests/test_semantic_validator.py + tests/test_sdk_core.py + tests/test_sdk_fixture_roundtrip.py + tests/test_cli.py +) + +supporting_files=( + LICENSE + CODE_OF_CONDUCT.md + CONTRIBUTING.md + GOVERNANCE.md + SECURITY.md + requirements.txt + .github/CODEOWNERS + .github/PULL_REQUEST_TEMPLATE.md + .github/workflows/validate.yml +) -grep -q "Public demo receipts in this repository are not production-valid receipts" README.md \ - || fail "README must state that public demo receipts are not production-valid" -grep -q "Production-valid receipts require authorized issuer access through Passpod Hub and the Pilot Access Engine" README.md \ - || fail "README must state the production-valid receipt access boundary" -grep -q "Passpod TASK Core -> Passpod Hub -> Control Packs -> Pilot Access -> paid pilot / Team / Enterprise" README.md \ - || fail "README missing canonical product stack" - -for term in \ - "Passpod TASK Core" \ - "Passpod Hub" \ - "Control Packs" \ - "AgentTrust" \ - "Remote Worker Trust" \ - "Pilot Access Engine" \ - "Trust Action Receipt" \ - "Sensitive Action Control" \ - "DIDX" -do - grep -R "$term" README.md SPEC.md docs/glossary.md PILOT_ACCESS.md ADOPTION.md LAUNCH_READINESS.md COMMERCIAL_BOUNDARY.md >/dev/null \ - || fail "Canonical term missing from public docs: $term" +for path in "${canonical_files[@]}" "${supporting_files[@]}"; do + require_file "$path" done -grep -R "Passpod Hub is the paid hosted product layer" README.md COMMERCIAL_BOUNDARY.md >/dev/null \ - || fail "Public docs must distinguish TASK Core from Passpod Hub" -grep -R "production issuer logic" README.md SPEC.md ADOPTION.md LAUNCH_READINESS.md COMMERCIAL_BOUNDARY.md cli/README.md worker-reference/README.md openapi/README.md >/dev/null \ - || fail "Public docs must exclude production issuer logic" -grep -R "Sentinel/Ops internals" ADOPTION.md LAUNCH_READINESS.md COMMERCIAL_BOUNDARY.md >/dev/null \ - || fail "Public docs must exclude Sentinel/Ops internals" - -for readme in examples/README.md openapi/README.md validator/README.md cli/README.md worker-reference/README.md; do - if grep -Eiq 'placeholder|skeleton placeholder|TODO|TBD|coming soon|lorem|fixme' "$readme"; then - fail "Public directory README still contains placeholder-only language: $readme" - fi +require_dir examples/valid +require_dir examples/invalid +require_dir schemas +require_dir validator +require_dir passpod +require_dir tests + +canonical_schema_files=( + schemas/message.schema.json + schemas/handshake.schema.json + schemas/profile.schema.json +) + +canonical_valid_fixtures=( + examples/valid/minimal-propose.json + examples/valid/propose-challenge.json + examples/valid/propose-challenge-agree.json + examples/valid/complete-handshake.json + examples/valid/minimal-profile.json +) + +canonical_invalid_fixtures=( + examples/invalid/missing-parent.json + examples/invalid/invalid-transition.json + examples/invalid/close-before-agree.json + examples/invalid/duplicate-message-id.json + examples/invalid/redefine-message-type.json +) + +for path in "${canonical_schema_files[@]}" "${canonical_valid_fixtures[@]}" "${canonical_invalid_fixtures[@]}"; do + require_file "$path" + require_json "$path" done -dangerous_patterns='SECRET=|PRIVATE_KEY=|BEGIN PRIVATE KEY|real customer receipt:|production signing key:|scoped key value|sk_live_|pk_live_|AKIA[0-9A-Z]{16}|production-valid receipt issuance|production-valid issuance|full monetization workflow|exit roadmap:' +require_contains README.md "PROPOSE -> CHALLENGE -> AGREE -> CLOSE" \ + "README to present the canonical four-message handshake flow" +require_contains README.md "transport-neutral" \ + "README to position Passpod as transport-neutral" +require_contains docs/STANDARD.md "transport-neutral" \ + "the Standard to preserve transport neutrality" +require_contains docs/STANDARD.md "append-only" \ + "the Standard to preserve append-only handshake history" +require_contains docs/STANDARD.md "immutable accepted messages" \ + "the Standard to preserve immutable accepted messages" +require_contains docs/PROTOCOL.md "PROPOSE -> CHALLENGE -> AGREE -> CLOSE" \ + "the Protocol to preserve the canonical handshake flow" +require_contains docs/PROTOCOL.md "The handshake history is append-only" \ + "the Protocol to preserve append-only history" +require_contains docs/PROTOCOL.md "a message is immutable" \ + "the Protocol to preserve immutable accepted messages" +require_contains docs/STATE-MODEL.md "Closure is terminal" \ + "the State Model to preserve terminal closure" +require_contains docs/STATE-MODEL.md "closure ends active negotiation" \ + "the State Model to preserve closure as the end of active negotiation" +require_contains docs/PROFILES.md "Profiles specialize Passpod" \ + "Profiles to be specializations of Passpod" +require_contains docs/PROFILES.md "Profiles MUST NOT redefine" \ + "Profiles not to redefine the protocol" +require_contains docs/CONFORMANCE.md "Semantic conformance" \ + "Conformance to preserve semantic conformance" +require_contains docs/TERMINOLOGY.md "## Archived Legacy Terminology" \ + "Terminology to isolate archived legacy terminology" + +PYTHONDONTWRITEBYTECODE=1 python3 - <<'PY' || fail "Legacy terminology containment failed; expected archived-only context in active public files" +from pathlib import Path +import sys + +legacy_terms = ( + "TASK", + "TASK Core", + "TASK Guard", + "Sensitive Action Control", + "Trust Action Receipt", + "Passpod Hub", + "AgentTrust", + "Control Packs", + "Pilot Access Engine", + "Kill-State", +) + +active_sections = ( + ("README.md", "## Legacy Terminology"), + ("docs/QUICKSTART.md", "## Unsupported Behavior"), + ("docs/TERMINOLOGY.md", "## Archived Legacy Terminology"), + ("docs/STANDARD.md", None), + ("docs/PROTOCOL.md", None), + ("docs/STATE-MODEL.md", None), + ("docs/MESSAGE-MODEL.md", None), + ("docs/PROFILES.md", None), + ("docs/CONFORMANCE.md", None), +) + +for path_text, marker in active_sections: + path = Path(path_text) + text = path.read_text(encoding="utf-8") + active = text.split(marker, 1)[0] if marker else text + for term in legacy_terms: + if term in active: + print( + f"{path_text}: active section contains legacy term {term!r}; " + "expected historical or migration-only context", + file=sys.stderr, + ) + raise SystemExit(1) +PY + +PYTHONDONTWRITEBYTECODE=1 python3 - <<'PY' || fail "Relative link audit failed; expected README and quickstart links to resolve" +from pathlib import Path +import re +import sys + +root = Path(".").resolve() +paths = [Path("README.md"), Path("docs/QUICKSTART.md")] +missing = [] + +for path in paths: + text = path.read_text(encoding="utf-8") + for target in re.findall(r"\[[^\]]+\]\(([^)]+)\)", text): + if "://" in target or target.startswith("#"): + continue + target_path = (path.parent / target).resolve() + try: + target_path.relative_to(root) + except ValueError: + missing.append(f"{path}: {target} escapes repository root") + continue + if not target_path.exists(): + missing.append(f"{path}: {target}") + +if missing: + for entry in missing: + print(entry, file=sys.stderr) + raise SystemExit(1) +PY + +PYTHONDONTWRITEBYTECODE=1 python3 - <<'PY' || fail "SDK import check failed: passpod package; expected Message, Handshake, Profile, PasspodValidationError, and importable CLI" +import passpod +from passpod import Handshake, Message, PasspodValidationError, Profile +import passpod.cli + +for name in ("Message", "Handshake", "Profile", "PasspodValidationError"): + if not hasattr(passpod, name): + raise SystemExit(f"missing package-root export: {name}") + +for value in (Message, Handshake, Profile, PasspodValidationError, passpod.cli): + if value is None: + raise SystemExit("unexpected empty SDK or CLI import") +PY + +ds_store_paths="$(find . -path './.git' -prune -o -name '.DS_Store' -print)" +if [ -n "$ds_store_paths" ]; then + fail "Generated operating-system file found: $ds_store_paths; expected no .DS_Store files" +fi + +sensitive_local_paths="$(find . -path './.git' -prune -o \( -name '.env' -o -name '.env.local' -o -name '.env.production' -o -name '.env.development' -o -name 'id_rsa' -o -name 'id_dsa' -o -name '*.pem' -o -name '*.p12' -o -name '*.pfx' \) -type f -print)" +if [ -n "$sensitive_local_paths" ]; then + fail "Sensitive local file found: $sensitive_local_paths; expected no local secrets, credentials, or private keys" +fi + +dangerous_patterns='SECRET=|PRIVATE_KEY=|BEGIN PRIVATE KEY|real customer receipt:|production signing key:|scoped key value|sk_live_|pk_live_|AKIA[0-9A-Z]{16}|private pilot record:|private pilot submission:|customer workflow dump:|full monetization workflow|exit roadmap:' if grep -R -E "$dangerous_patterns" . \ --exclude-dir=.git \ - --exclude="check-public-task-repo.sh" \ - --exclude="seed_passpod_task.py" >/dev/null; then - fail "Dangerous secret/private leakage pattern found" + --exclude="check-public-task-repo.sh" >/dev/null; then + fail "Dangerous secret/private leakage pattern found; expected public repository boundary to exclude credentials and private operational records" fi -python3 tools/validate-receipts.py -echo "✅ Public TASK repo gate passed" +echo "Passpod v0.1 public repository gate passed" From c9a497af0488f69d435013e69c30601163aef579 Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 03:28:54 +0800 Subject: [PATCH 07/18] Migrate CI and PR checks to Passpod v0.1 --- .github/PULL_REQUEST_TEMPLATE.md | 51 ++++++++++++++++++++++++++------ .github/workflows/validate.yml | 38 +++++++++++++++++------- 2 files changed, 70 insertions(+), 19 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 95e75ac..1060862 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,9 +1,42 @@ -## Public TASK repo checklist - -- [ ] No private customer data -- [ ] No production keys -- [ ] No scoped key internals -- [ ] No buyer-specific workflows -- [ ] No commercial backend logic -- [ ] Example receipts are sanitized -- [ ] `bash tools/check-public-task-repo.sh` passes +## Passpod v0.1 checklist + +### Scope + +- [ ] Change is bounded and described. +- [ ] Unrelated files are not modified. +- [ ] Active architecture is not redesigned unintentionally. + +### Canonical semantics + +- [ ] Preserves `PROPOSE -> CHALLENGE -> AGREE -> CLOSE`. +- [ ] Preserves transport neutrality. +- [ ] Preserves append-only history. +- [ ] Preserves immutable accepted messages. +- [ ] Preserves terminal closure. +- [ ] Profiles do not redefine core message meanings. + +### Implementation + +- [ ] Existing schemas remain authoritative for structure. +- [ ] Semantic validator remains authoritative for bounded protocol validity. +- [ ] SDK and CLI do not introduce new semantics. +- [ ] No unsupported transport, persistence, signature, cryptographic, or identity claims are added. + +### Validation + +- [ ] `PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests` +- [ ] `bash tools/check-public-task-repo.sh` (Passpod v0.1 repository gate) + +### Security and privacy + +- [ ] No secrets, credentials, private keys, tokens, or private pilot records. +- [ ] No sensitive local files. +- [ ] Inspection output does not expose full private payloads. +- [ ] No new network behavior unless explicitly scoped in a later approved transport pass. + +### Documentation + +- [ ] Active terminology matches Passpod v0.1. +- [ ] Archived terms appear only in migration or historical context. +- [ ] Links and commands are verified. +- [ ] Claims do not overstate production readiness, adoption, certification, cryptography, or deployment. diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 74b931c..7e557cf 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -1,4 +1,4 @@ -name: Validate TASK public repo +name: Validate Passpod v0.1 on: pull_request: @@ -9,16 +9,34 @@ permissions: contents: read jobs: - validate: + validate-passpod: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Install validator dependencies - run: python -m pip install -r requirements.txt - - name: Validate JSON and public repo gate + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install Python dependencies + run: python3 -m pip install -r requirements.txt + + - name: Check canonical JSON files parse run: | - python -m json.tool schemas/trust-action-receipt.schema.json >/dev/null - python -m json.tool examples/remote-worker.receipt.json >/dev/null - python -m json.tool examples/agent-freeze.receipt.json >/dev/null - python -m json.tool examples/refund-review.receipt.json >/dev/null - bash tools/check-public-task-repo.sh + set -euo pipefail + for json_file in \ + schemas/message.schema.json \ + schemas/handshake.schema.json \ + schemas/profile.schema.json \ + examples/valid/*.json \ + examples/invalid/*.json + do + python3 -m json.tool "$json_file" >/dev/null + done + + - name: Run Python test suite + run: PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests + + - name: Run Passpod v0.1 repository gate + run: bash tools/check-public-task-repo.sh From b776a7d56b048dbbb70c06fc28b38787f194c4bb Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 03:39:20 +0800 Subject: [PATCH 08/18] Archive legacy receipt schema and examples --- README.md | 2 +- SPEC.md | 2 +- archive/legacy-task/README.md | 56 +++++++++++++++++++ .../examples}/agent-freeze.receipt.json | 0 .../examples}/refund-review.receipt.json | 0 .../examples}/remote-worker.receipt.json | 0 .../schemas}/trust-action-receipt.schema.json | 0 docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md | 2 + docs/PASSPOD-RESET-AUDIT.md | 3 +- examples/README.md | 18 +++--- tools/pilot-readiness.py | 2 +- tools/validate-receipts.py | 6 +- validator/README.md | 10 ++-- 13 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 archive/legacy-task/README.md rename {examples => archive/legacy-task/examples}/agent-freeze.receipt.json (100%) rename {examples => archive/legacy-task/examples}/refund-review.receipt.json (100%) rename {examples => archive/legacy-task/examples}/remote-worker.receipt.json (100%) rename {schemas => archive/legacy-task/schemas}/trust-action-receipt.schema.json (100%) diff --git a/README.md b/README.md index 1d1c087..2cae619 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ These terms are outside the active Passpod v0.1 architecture. They are preserved Historical migration references: - [Legacy specification](SPEC.md) -- [Legacy receipt schema](schemas/trust-action-receipt.schema.json) +- [Legacy receipt schema](archive/legacy-task/schemas/trust-action-receipt.schema.json) - [Legacy OpenAPI reference](openapi/passpod-task.public.yaml) - [Legacy examples guide](examples/README.md) - [Legacy validator guide](validator/README.md) diff --git a/SPEC.md b/SPEC.md index 607c0b2..2fa82da 100644 --- a/SPEC.md +++ b/SPEC.md @@ -26,7 +26,7 @@ were considered. A Trust Action Receipt is the portable output of a TASK decision. In this public v0.1 draft, a receipt is a JSON object that can be validated -against `schemas/trust-action-receipt.schema.json`. A schema-valid public +against `archive/legacy-task/schemas/trust-action-receipt.schema.json`. A schema-valid public receipt means the object follows the draft shape. It does not mean the receipt was issued by a production service, signed by a production issuer, stored by a hosted verification service, or accepted for a real workflow. diff --git a/archive/legacy-task/README.md b/archive/legacy-task/README.md new file mode 100644 index 0000000..074438a --- /dev/null +++ b/archive/legacy-task/README.md @@ -0,0 +1,56 @@ +# Legacy TASK Archive + +## Status + +This directory contains superseded TASK-era material. It is retained for history, migration analysis, and provenance. + +This material is not canonical Passpod v0.1. Trust Action Receipts are not the primary protocol object in Passpod v0.1. + +## Historical Context + +The archived schema and examples come from the earlier TASK receipt family. They describe historical Trust Action Receipt concepts, demo receipt examples, and receipt-era tooling inputs. + +Passpod v0.1 is defined by the Standard, Handshake Protocol, State Model, Message Model, Profile model, Conformance model, canonical schemas, canonical fixtures, semantic validator, SDK core, and CLI. + +## Archived Contents + +- [schemas/trust-action-receipt.schema.json](schemas/trust-action-receipt.schema.json) +- [examples/remote-worker.receipt.json](examples/remote-worker.receipt.json) +- [examples/refund-review.receipt.json](examples/refund-review.receipt.json) +- [examples/agent-freeze.receipt.json](examples/agent-freeze.receipt.json) + +## Canonical Passpod v0.1 Replacements + +Active schemas are: + +- [../../schemas/message.schema.json](../../schemas/message.schema.json) +- [../../schemas/handshake.schema.json](../../schemas/handshake.schema.json) +- [../../schemas/profile.schema.json](../../schemas/profile.schema.json) + +Active fixtures are under: + +- [../../examples/valid/](../../examples/valid/) +- [../../examples/invalid/](../../examples/invalid/) + +## Usage Warning + +Archived examples must not be used to infer current protocol semantics. They are legacy receipt examples, not Passpod v0.1 messages, handshakes, profiles, or conformance fixtures. + +Do not convert these artifacts into canonical handshakes by assumption. Any future migration of a legacy scenario requires a bounded profile or fixture design pass. + +## Legacy Consumers + +The following legacy consumers may still mention or load archived receipt-era material: + +- `tools/validate-receipts.py` +- `tools/pilot-readiness.py` +- `validator/README.md` +- `examples/README.md` +- `SPEC.md` +- `openapi/passpod-task.public.yaml` + +These consumers are retained as historical legacy material. They do not define the active Passpod v0.1 architecture. + +## Provenance + +The files in this directory were moved from the repository root schema and example locations using `git mv` so Git history remains traceable. diff --git a/examples/agent-freeze.receipt.json b/archive/legacy-task/examples/agent-freeze.receipt.json similarity index 100% rename from examples/agent-freeze.receipt.json rename to archive/legacy-task/examples/agent-freeze.receipt.json diff --git a/examples/refund-review.receipt.json b/archive/legacy-task/examples/refund-review.receipt.json similarity index 100% rename from examples/refund-review.receipt.json rename to archive/legacy-task/examples/refund-review.receipt.json diff --git a/examples/remote-worker.receipt.json b/archive/legacy-task/examples/remote-worker.receipt.json similarity index 100% rename from examples/remote-worker.receipt.json rename to archive/legacy-task/examples/remote-worker.receipt.json diff --git a/schemas/trust-action-receipt.schema.json b/archive/legacy-task/schemas/trust-action-receipt.schema.json similarity index 100% rename from schemas/trust-action-receipt.schema.json rename to archive/legacy-task/schemas/trust-action-receipt.schema.json diff --git a/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md b/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md index 9cffa20..81346d4 100644 --- a/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md +++ b/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md @@ -1,5 +1,7 @@ # Canonical Repository Migration Map +Post-archival note: receipt-era schema and example paths quoted in this migration map describe repository state and dependencies observed when the map was written. The legacy receipt family now lives under `archive/legacy-task/`; any former active paths retained below are historical dependency evidence, not active Passpod v0.1 requirements. + ## 1. Executive Summary This audit reviewed every tracked repository asset after the Passpod v0.1 reset. diff --git a/docs/PASSPOD-RESET-AUDIT.md b/docs/PASSPOD-RESET-AUDIT.md index bb471f7..f3a167f 100644 --- a/docs/PASSPOD-RESET-AUDIT.md +++ b/docs/PASSPOD-RESET-AUDIT.md @@ -6,6 +6,8 @@ Branch observed: `main` Remote observed: `https://github.com/edidx/passpod-task.git` Audit mode: read-only audit plus this single new report file +Post-archival note: legacy receipt schema and receipt example paths referenced by their former active locations in this historical audit have since been moved to `archive/legacy-task/`. Those former paths remain in this report as observations of repository state at audit time, not active Passpod v0.1 requirements. + ## 1. Executive summary The current repository is implemented as a public "Passpod TASK Core" standard/test repository. It is not yet aligned with the reset architecture: @@ -386,4 +388,3 @@ Observed validation output: - Whether `Remote Worker` should become a canonical Reference Profile or be archived is not inferable from this repo alone. - Whether external clients use `openapi/passpod-task.public.yaml` is not inferable from local imports. - Empty local directories `packages/validator/`, `spec/`, and `src/` are not tracked by git; their intended purpose is unknown. - diff --git a/examples/README.md b/examples/README.md index c2a750e..7effa30 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,10 +1,12 @@ -# Example Receipts +# Archived Receipt Examples -This directory contains public demo Trust Action Receipts for Passpod TASK Core. -They are intentionally sanitized examples for learning, schema validation, and -tooling tests. +The Trust Action Receipt examples described here are archived under +[`../archive/legacy-task/examples/`](../archive/legacy-task/examples/). They are +superseded TASK-era material retained for history, migration analysis, and +provenance. -These receipts are valid public examples, not production-valid receipts. They +These receipts are legacy public examples, not canonical Passpod v0.1 fixtures +and not production-valid receipts. They use `demo-signature-not-production` and do not include production receipt IDs, policy references, proof references, customer workflows, issuer internals, or scoped key logic. @@ -12,7 +14,7 @@ scoped key logic. Production-valid receipts require authorized issuer access through Passpod Hub and the Pilot Access Engine. -## remote-worker.receipt.json +## [remote-worker.receipt.json](../archive/legacy-task/examples/remote-worker.receipt.json) Demonstrates a Remote Worker TrustPass-style reference check. @@ -22,7 +24,7 @@ Demonstrates a Remote Worker TrustPass-style reference check. - Why it matters: work-reference requests should collect consent and context before a trust decision is made. -## refund-review.receipt.json +## [refund-review.receipt.json](../archive/legacy-task/examples/refund-review.receipt.json) Demonstrates a high-risk refund approval that needs review before execution. @@ -31,7 +33,7 @@ Demonstrates a high-risk refund approval that needs review before execution. - `decision`: `review_required` - Why it matters: large or risky refund actions should not execute silently. -## agent-freeze.receipt.json +## [agent-freeze.receipt.json](../archive/legacy-task/examples/agent-freeze.receipt.json) Demonstrates a freeze decision for abnormal agent behavior. diff --git a/tools/pilot-readiness.py b/tools/pilot-readiness.py index 7618cba..a4fbd01 100755 --- a/tools/pilot-readiness.py +++ b/tools/pilot-readiness.py @@ -3,7 +3,7 @@ from pathlib import Path if len(sys.argv) != 2: - print("Usage: python3 tools/pilot-readiness.py examples/remote-worker.receipt.json") + print("Usage: python3 tools/pilot-readiness.py archive/legacy-task/examples/remote-worker.receipt.json") raise SystemExit(2) data = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8")) diff --git a/tools/validate-receipts.py b/tools/validate-receipts.py index dd47a28..43dd24e 100755 --- a/tools/validate-receipts.py +++ b/tools/validate-receipts.py @@ -8,8 +8,8 @@ raise SystemExit("Missing dependency. Run: python3 -m pip install -r requirements.txt") from exc -SCHEMA_PATH = Path("schemas/trust-action-receipt.schema.json") -EXAMPLES_DIR = Path("examples") +SCHEMA_PATH = Path("archive/legacy-task/schemas/trust-action-receipt.schema.json") +EXAMPLES_DIR = Path("archive/legacy-task/examples") DEMO_SIGNATURE = "demo-signature-not-production" FORBIDDEN_PUBLIC_MARKERS = ( "BEGIN " + "PRIVATE KEY", @@ -59,7 +59,7 @@ def main(): ok = True if not paths: - print("❌ examples: no *.receipt.json files found") + print(f"❌ {EXAMPLES_DIR}: no *.receipt.json files found") return 1 for path in paths: diff --git a/validator/README.md b/validator/README.md index 90d626b..4657c4b 100644 --- a/validator/README.md +++ b/validator/README.md @@ -1,12 +1,12 @@ -# Validator +# Legacy Receipt Validator -The public validator checks the example Trust Action Receipts against the -public JSON Schema and the demo-only safety boundary. +The legacy receipt validator checks archived Trust Action Receipt examples +against the public JSON Schema and the demo-only safety boundary. It validates that: -- each `examples/*.receipt.json` file is JSON; -- each example matches `schemas/trust-action-receipt.schema.json`; +- each `archive/legacy-task/examples/*.receipt.json` file is JSON; +- each example matches `archive/legacy-task/schemas/trust-action-receipt.schema.json`; - public examples keep `demo-signature-not-production`; - public examples do not claim production receipt IDs, policy references, or proof references. From 22a5fed96b05462e2e61e06d66737fd94f824f84 Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 03:45:17 +0800 Subject: [PATCH 09/18] Decide legacy OpenAPI and transport material treatment --- docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md | 338 ++++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100644 docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md diff --git a/docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md b/docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md new file mode 100644 index 0000000..f362cac --- /dev/null +++ b/docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md @@ -0,0 +1,338 @@ +# OpenAPI Transport Material Decision + +## 1. Executive Summary + +This audit reviewed the remaining OpenAPI, worker-reference, API documentation, and transport-oriented material after the Passpod v0.1 specification, schemas, fixtures, validator, SDK, CLI, README, quickstart, gate, CI, and legacy receipt archive were completed. + +Baseline was clean: + +```text +git status --short +``` + +returned no output, and: + +```text +git log -9 --oneline +``` + +showed `b776a7d Archive legacy receipt schema and examples` as the latest commit. + +Finding: the current OpenAPI and worker-reference family is not canonical Passpod v0.1. It is a legacy TASK/receipt/Hub-oriented public reference shape. It has no active runtime, SDK, CLI, test, CI, package-script, or validator dependency. The only current public inbound link is the README legacy OpenAPI link, and historical audit/migration documents reference it as legacy material. + +Decision: classify `openapi/passpod-task.public.yaml`, `openapi/README.md`, and `worker-reference/README.md` as `ARCHIVE WITH LEGACY TASK`. + +Recommended next bounded pass: Archive legacy OpenAPI and worker-reference family. + +## 2. Audit Scope + +Audited files and locations: + +- `openapi/passpod-task.public.yaml` +- `openapi/README.md` +- `worker-reference/README.md` +- README legacy references +- SPEC legacy transport references +- API-oriented references in `docs/`, `examples/`, `tools/`, `validator/`, `cli/`, `.github/`, tests, schemas, SDK code, and package metadata + +Search coverage included: + +- `openapi/` +- `passpod-task.public.yaml` +- `worker-reference/` +- `HTTP` +- `REST` +- `endpoint` +- `webhook` +- `server` +- `sandbox` +- `issue` +- `verify` +- `revoke` +- `receipt` +- `Hub` +- `Pilot Access Engine` +- `API key` +- `scoped key` + +Package metadata found: + +- `requirements.txt` + +No `package.json`, `pyproject.toml`, `setup.py`, `setup.cfg`, Makefile, tox config, nox config, API-client package, generated API docs, or API-specific package script was found. + +## 3. Passpod Transport-Neutral Boundary + +Passpod v0.1 is transport-neutral. The canonical architecture is: + +- Passpod Standard +- Passpod Handshake Protocol +- State Model +- Message Model +- Profiles +- Conformance +- SDK +- Pilot + +The canonical protocol flow is: + +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` + +HTTP, REST, OpenAPI, webhooks, queues, wallets, files, and other transports are not the core protocol. A future OpenAPI document may describe an optional HTTP binding or service implementation, but it must not become the source of Passpod semantics. + +Current source-of-truth evidence: + +- `docs/STANDARD.md` says the Standard does not define HTTP routes, APIs, webhooks, or transports. +- `docs/PROTOCOL.md` says the protocol does not depend on HTTP, queues, email, files, ledgers, databases, blockchains, wallets, browsers, or any other transport. +- `docs/QUICKSTART.md` lists HTTP API as unsupported behavior. +- `.github/PULL_REQUEST_TEMPLATE.md` requires preserving transport neutrality. + +## 4. OpenAPI Inventory + +| Asset | Finding | +|---|---| +| Path | `openapi/passpod-task.public.yaml` | +| OpenAPI version | `3.1.0` | +| Title | `Passpod TASK Public Reference API` | +| API version | `0.1.0-draft` | +| Server URL | `https://api.passpod.example` | +| Tags | `Spec`, `Receipts` | +| Paths | `GET /v1/spec`, `POST /v1/receipts/validate`, `GET /v1/receipts/{receipt_id}` | +| Operation IDs | `getTaskSpec`, `validateTrustActionReceipt`, `getReceiptById` | +| Request models | `TrustActionReceipt` for receipt validation | +| Response models | `PublicSpec`, `ReceiptValidationResult`, `ReceiptLookupResult`, `ErrorResponse` | +| Security schemes | None found | +| External schema references | No external `$ref`; example value references `https://passpod.io/schemas/trust-action-receipt.schema.json` | +| Internal `$ref` usage | Component schemas reference each other within the same OpenAPI document | +| Receipt-era operations | Spec metadata points to receipt schema; receipt validation; receipt lookup | +| Hub assumptions | Description excludes Passpod Hub internals but frames production validity through legacy Hub/Pilot concepts | +| Pilot Access Engine assumptions | No literal `Pilot Access Engine` in YAML, but `Pilot Access` appears in contact and hosted-verification text | +| Generated-code consumers | None found | +| Documentation consumers | README legacy link, `openapi/README.md`, reset audit, migration map, archive README | +| Runtime consumers | None found | +| Test consumers | None found | +| CI consumers | None found | +| Package-script consumers | None found | + +OpenAPI character: + +| Question | Determination | +|---|---| +| Does it describe the core protocol correctly? | No. It does not model `PROPOSE`, `CHALLENGE`, `AGREE`, or `CLOSE`. | +| Does it describe a legacy hosted TASK service? | Mostly yes. It is a public TASK receipt validation and lookup reference. | +| Is it a potentially reusable optional HTTP binding? | Only at the concept level: metadata, validation, and lookup could inform later work. | +| Is it a mixture? | Yes. It contains reusable API-boundary patterns, but the concrete semantics are legacy receipt-primary semantics. | + +## 5. OpenAPI Semantic Comparison + +| Operation | Current semantics | Passpod v0.1 mapping | Classification | +|---|---|---|---| +| `GET /v1/spec` | Returns public TASK draft metadata and a receipt schema URL. | Does not map to a canonical message. Could inspire future non-semantic metadata discovery only. | Potentially adaptable later, but currently legacy. | +| `POST /v1/receipts/validate` | Validates a Trust Action Receipt against receipt-era schema and public demo safety rules. | Does not create or submit `PROPOSE`, return `CHALLENGE`, record `AGREE`, record `CLOSE`, or validate a canonical handshake. | Reusable validation concept; incompatible legacy operation as written. | +| `GET /v1/receipts/{receipt_id}` | Defines receipt lookup response shape and hosted-verification boundary. | Could loosely resemble artifact inspection in a future service, but current object is receipt lookup, not handshake inspection. | Potentially adaptable later; currently legacy. | + +Legacy concepts present: + +- Trust Action Receipt as primary object +- receipt validation +- receipt lookup +- `allow`, `deny`, `review_required`, `freeze`, `revoke` decision enum +- production issuance boundary +- hosted verification boundary +- Pilot Access contact and assumptions +- Passpod Hub exclusions +- legacy public schema URL + +Legacy operations not present as explicit OpenAPI paths: + +- issue receipt +- verify receipt +- revoke receipt +- scoped pilot key creation +- hosted Hub workflow execution + +The absence of explicit issue, verify, revoke, or key routes lowers immediate runtime risk, but it does not make the OpenAPI document canonical. + +## 6. Worker-Reference Inventory + +| Asset | Finding | +|---|---| +| Path | `worker-reference/README.md` | +| Language/runtime | Documentation only; no code found | +| Implemented endpoints | None | +| Validation behavior | None implemented | +| Signing behavior | None implemented | +| Storage behavior | None implemented | +| Demo behavior | Describes a possible future public validation Worker around TASK Core receipts | +| Legacy schema imports | None | +| README references | No active README link found | +| Package scripts | None found | +| Tests | None found | +| CI references | None found | +| Deployment config | None found | +| Reusable transport-neutral logic | None found | +| Future optional HTTP reference value | Very low as-is because the only tracked file is receipt/HUB-oriented documentation | + +The worker-reference directory is not an implementation. It is a reserved documentation placeholder for a future Worker framed around public demo receipt validation and legacy Hub/Pilot Access Engine boundaries. + +## 7. API Documentation and Tooling References + +| Location | Reference type | Classification | +|---|---|---| +| `README.md` | Legacy OpenAPI link in historical migration references | Explicit historical mention | +| `openapi/README.md` | Describes OpenAPI TASK receipt endpoints | Active legacy API material | +| `openapi/passpod-task.public.yaml` | OpenAPI API shape | Active legacy API material | +| `worker-reference/README.md` | Future Worker placeholder around TASK receipts | Active legacy API material | +| `SPEC.md` | Hosted lookup, receipt issuance, Hub, Pilot Access Engine wording | Historical legacy specification | +| `ADOPTION.md` | Mentions OpenAPI reference and scoped Hub access | Historical legacy public-surface material | +| `PILOT_ACCESS.md` | Hosted/scoped pilot access language | Deferred pilot/commercial material | +| `COMMERCIAL_BOUNDARY.md` | Hub/Pilot Access Engine public/private boundary | Deferred commercial material | +| `docs/public-vs-pilot.md` | Hosted endpoint and signed pilot receipt wording | Deferred pilot boundary material | +| `docs/STANDARD.md` | Says HTTP/API/webhooks/transports are non-goals | Canonical transport-neutral reference | +| `docs/PROTOCOL.md` | Says protocol is independent of transports | Canonical transport-neutral reference | +| `docs/QUICKSTART.md` | Lists HTTP API as unsupported | Canonical transport-neutral reference | +| `tools/check-public-task-repo.sh` | Canonical gate plus public/private leakage patterns | Implementation-neutral support | +| `.github/workflows/validate.yml` | Canonical tests and gate only | Implementation-neutral support | +| `.github/PULL_REQUEST_TEMPLATE.md` | Requires preserving transport neutrality | Implementation-neutral support | +| `tools/validate-receipts.py` | Legacy receipt validator, no HTTP behavior | Historical supporting utility | +| `tools/pilot-readiness.py` | Legacy receipt readiness scoring, no HTTP behavior | Deferred pilot utility | +| `tests/`, `passpod/`, `validator/semantic_validator.py` | No OpenAPI or worker-reference references found | No transport dependency | + +No webhook documentation, sandbox API material, API-client helper, generated API documentation, transport-specific tests, or package scripts invoking API material were found. + +## 8. Dependency Map + +| Asset | Current purpose | Inbound links | Outbound refs | Runtime consumers | Test/CI consumers | Package consumers | Public URL assumptions | Migration risk | Classification | Proposed future action | Required predecessors | +|---|---|---|---|---|---|---|---|---|---|---|---| +| `openapi/passpod-task.public.yaml` | Legacy TASK receipt API reference | README legacy link; `openapi/README.md`; audit/migration docs; archive README | Internal component `$ref`; example `receipt_schema` URL; LICENSE metadata; Pilot Access contact | None | None | None | `https://api.passpod.example`; `https://passpod.io/schemas/trust-action-receipt.schema.json` | Medium: public link and possible external readers, but no local canonical dependency | ARCHIVE WITH LEGACY TASK | Move under `archive/legacy-task/openapi/` in a later pass | Update README/archive links and verify links | +| `openapi/README.md` | Explains legacy OpenAPI reference | Audit/migration docs | `openapi/passpod-task.public.yaml` | None | None | None | None beyond referenced file | Low to medium: must move with YAML to avoid orphaned doc | ARCHIVE WITH LEGACY TASK | Move with OpenAPI YAML | Same as OpenAPI YAML | +| `worker-reference/README.md` | Reserved future Worker placeholder around TASK receipts | Audit/migration docs | None | None | None | None | None | Low: no code, no active consumer | ARCHIVE WITH LEGACY TASK | Move under legacy archive with OpenAPI family | Verify no README/CI/test link is introduced | +| `README.md` legacy OpenAPI link | Historical navigation | Public README | `openapi/passpod-task.public.yaml` | None | Link audit in gate | None | None | Medium because public README link must keep resolving | RETAIN AS HISTORICAL SUPPORTING MATERIAL | Update link only during archive pass | Archive destination must exist | +| `archive/legacy-task/README.md` legacy consumer list | Provenance of receipt-era material | None | Mentions OpenAPI as remaining legacy consumer | None | None | None | None | Low | RETAIN AS HISTORICAL SUPPORTING MATERIAL | Update list if OpenAPI moves | Archive destination must exist | +| `tools/check-public-task-repo.sh` | Canonical v0.1 public gate | CI, PR template | Canonical docs/schemas/fixtures only; no OpenAPI dependency | Local command | CI | None | None | Low for this pass | KEEP AS IMPLEMENTATION-NEUTRAL SUPPORT | Leave unchanged | None | +| `.github/workflows/validate.yml` | Canonical CI | GitHub Actions | Canonical JSON, tests, gate | CI | CI | None | None | Low | KEEP AS IMPLEMENTATION-NEUTRAL SUPPORT | Leave unchanged | None | + +## 9. Stable Identifier and URL Findings + +| Identifier or URL | Location | Finding | Treatment | +|---|---|---|---| +| `https://api.passpod.example` | OpenAPI server URL | Placeholder reference URL; no evidence it is live or canonical | Preserve until archival; do not reinterpret | +| `https://passpod.io/schemas/trust-action-receipt.schema.json` | OpenAPI example and archived schema `$id` | Stable legacy schema identifier; filesystem archival does not require changing it | Preserve as legacy identifier | +| `/v1/spec` | OpenAPI path | Legacy TASK metadata route | Archive with OpenAPI | +| `/v1/receipts/validate` | OpenAPI path | Legacy receipt validation route | Archive with OpenAPI | +| `/v1/receipts/{receipt_id}` | OpenAPI path | Legacy receipt lookup route | Archive with OpenAPI | +| `getTaskSpec` | OpenAPI operation ID | Legacy TASK operation ID | Archive with OpenAPI | +| `validateTrustActionReceipt` | OpenAPI operation ID | Legacy receipt operation ID | Archive with OpenAPI | +| `getReceiptById` | OpenAPI operation ID | Legacy receipt operation ID | Archive with OpenAPI | +| `pilots@passpod.io` | OpenAPI contact and legacy docs | Public pilot contact, not proof of an active API | Defer to pilot/commercial policy | + +Stable URL distinction: + +- Do not change schema `$id` values merely because files moved. +- Do not assume placeholder server URLs are live. +- Do not treat OpenAPI path names as Passpod protocol semantics. + +## 10. Classification by Asset + +| Classification | Count | Assets | +|---|---:|---| +| ARCHIVE WITH LEGACY TASK | 3 | `openapi/passpod-task.public.yaml`, `openapi/README.md`, `worker-reference/README.md` | +| RETAIN AS HISTORICAL SUPPORTING MATERIAL | 7 | `README.md` legacy OpenAPI link, `SPEC.md`, `ADOPTION.md`, `examples/README.md`, `validator/README.md`, `cli/README.md`, `archive/legacy-task/README.md` | +| MIGRATE LATER INTO OPTIONAL HTTP BINDING | 0 | None as concrete assets; only abstract concepts were reusable | +| KEEP AS IMPLEMENTATION-NEUTRAL SUPPORT | 5 | `docs/STANDARD.md`, `docs/PROTOCOL.md`, `docs/QUICKSTART.md`, `.github/workflows/validate.yml`, `tools/check-public-task-repo.sh` | +| DEFER | 4 | `PILOT_ACCESS.md`, `COMMERCIAL_BOUNDARY.md`, `docs/public-vs-pilot.md`, `tools/pilot-readiness.py` | +| DELETE-CANDIDATE | 0 | None | + +Reusable transport concepts found: + +- API metadata discovery could be useful later if clearly non-semantic. +- Artifact validation over HTTP could be useful later if it validates canonical messages, handshakes, profiles, or bundles. +- Artifact lookup or inspection could be useful later if scoped to canonical handshake inspection and privacy-preserving summaries. +- Public/private boundary language remains useful, but current wording is receipt/Hub/Pilot Access oriented. + +None of these concepts are sufficient to retain the current OpenAPI or worker-reference files on the active developer path. + +## 11. Future HTTP Binding Criteria + +Before Passpod may create an official optional HTTP binding, the binding must satisfy all of the following criteria: + +- It explicitly states that HTTP is optional and separate from the core protocol. +- It maps all four canonical message types: `PROPOSE`, `CHALLENGE`, `AGREE`, and `CLOSE`. +- It does not make receipts the primary protocol object. +- It does not hide hosted-service assumptions inside protocol semantics. +- It has versioning that is independent from the core Standard where appropriate. +- It defines a transport-specific conformance scope. +- It derives schemas from canonical message, handshake, and profile models. +- It includes tests proving transport behavior does not redefine protocol semantics. +- It states security and privacy boundaries clearly. +- It avoids production signing, storage, identity, cryptography, and hosted verification claims unless those are explicitly in scope for that binding. +- It does not claim that HTTP is required for Passpod conformance. +- It keeps profiles subordinate to the Standard, Protocol, State Model, Message Model, and Conformance model. + +This audit does not create that binding. + +## 12. Recommended Treatment + +| Material family | Selected treatment | Reason | +|---|---|---| +| OpenAPI family | Archive entire family now | The YAML and README are receipt/TASK/Hub-oriented, have no canonical consumer, and are already linked as legacy. | +| Worker-reference family | Archive entire family now | It contains only a legacy receipt-oriented placeholder README, no reusable code, no runtime, and no local consumer. | +| Legacy API documentation and receipt utilities | Retain frozen or defer | These are broader cleanup subjects and should not be bundled into the OpenAPI/worker move. | +| Canonical docs, schemas, fixtures, validator, SDK, CLI, tests, CI, gate | Keep unchanged | They are transport-neutral and do not depend on OpenAPI or worker-reference material. | + +The appropriate decision option is: + +```text +A. Archive entire family now +``` + +for both the OpenAPI family and the worker-reference family. + +## 13. Required Predecessor Actions + +Before the next archival pass moves files: + +1. Confirm the working tree is clean. +2. Move OpenAPI and worker-reference assets with `git mv`. +3. Update README legacy OpenAPI link to the archive location. +4. Update any archive README or migration-map links that would otherwise break. +5. Do not modify canonical docs, schemas, fixtures, SDK, CLI, tests, gate, or CI unless a direct moved-path link requires a minimal path update. +6. Verify relative links. +7. Run canonical tests and the Passpod v0.1 gate. +8. Confirm no API material remains on the active developer path. + +No external compatibility evidence was found locally. If external users rely on the OpenAPI file, that evidence is outside this repository and must be supplied by a later human decision. + +## 14. Explicit Non-actions + +This pass did not: + +- move OpenAPI files; +- move worker-reference files; +- rewrite OpenAPI; +- create an HTTP binding; +- create endpoints; +- create SDK transport code; +- create validators; +- create CLI code; +- modify README; +- modify SPEC; +- modify CI; +- modify the gate; +- modify canonical docs, schemas, fixtures, validator, SDK, CLI, or tests; +- commit; +- push. + +## 15. Final Recommendation + +The remaining OpenAPI and worker-reference material is legacy TASK transport material. It should not become canonical Passpod v0.1 and should not be used as the starting point for an HTTP binding without a separate design pass. + +Recommended next bounded pass: + +```text +Archive legacy OpenAPI and worker-reference family +``` + +Do not begin that pass from this report. From e8b5f4112fc46ad887ec3d1f8fcd744ea039e5b7 Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 03:51:57 +0800 Subject: [PATCH 10/18] Archive legacy OpenAPI and worker reference material --- README.md | 2 +- archive/legacy-task/README.md | 15 +++++++++++++-- .../legacy-task/openapi}/README.md | 2 +- .../legacy-task/openapi}/passpod-task.public.yaml | 0 .../legacy-task/worker-reference}/README.md | 0 docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md | 2 +- docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md | 2 ++ docs/PASSPOD-RESET-AUDIT.md | 2 +- 8 files changed, 19 insertions(+), 6 deletions(-) rename {openapi => archive/legacy-task/openapi}/README.md (89%) rename {openapi => archive/legacy-task/openapi}/passpod-task.public.yaml (100%) rename {worker-reference => archive/legacy-task/worker-reference}/README.md (100%) diff --git a/README.md b/README.md index 2cae619..517f2cd 100644 --- a/README.md +++ b/README.md @@ -176,7 +176,7 @@ Historical migration references: - [Legacy specification](SPEC.md) - [Legacy receipt schema](archive/legacy-task/schemas/trust-action-receipt.schema.json) -- [Legacy OpenAPI reference](openapi/passpod-task.public.yaml) +- [Legacy OpenAPI reference](archive/legacy-task/openapi/passpod-task.public.yaml) - [Legacy examples guide](examples/README.md) - [Legacy validator guide](validator/README.md) - [Legacy pilot access notes](PILOT_ACCESS.md) diff --git a/archive/legacy-task/README.md b/archive/legacy-task/README.md index 074438a..3e36338 100644 --- a/archive/legacy-task/README.md +++ b/archive/legacy-task/README.md @@ -18,6 +18,9 @@ Passpod v0.1 is defined by the Standard, Handshake Protocol, State Model, Messag - [examples/remote-worker.receipt.json](examples/remote-worker.receipt.json) - [examples/refund-review.receipt.json](examples/refund-review.receipt.json) - [examples/agent-freeze.receipt.json](examples/agent-freeze.receipt.json) +- [openapi/passpod-task.public.yaml](openapi/passpod-task.public.yaml) +- [openapi/README.md](openapi/README.md) +- [worker-reference/README.md](worker-reference/README.md) ## Canonical Passpod v0.1 Replacements @@ -38,6 +41,10 @@ Archived examples must not be used to infer current protocol semantics. They are Do not convert these artifacts into canonical handshakes by assumption. Any future migration of a legacy scenario requires a bounded profile or fixture design pass. +The archived OpenAPI document describes the previous receipt-oriented HTTP service shape. The worker-reference material belongs to the same historical transport family. Neither is part of the Passpod v0.1 core, neither defines current protocol semantics, and there is currently no canonical Passpod HTTP binding. + +Future HTTP binding work must be designed separately from the core protocol. The archival decision is documented in [../../docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md](../../docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md). + ## Legacy Consumers The following legacy consumers may still mention or load archived receipt-era material: @@ -47,10 +54,14 @@ The following legacy consumers may still mention or load archived receipt-era ma - `validator/README.md` - `examples/README.md` - `SPEC.md` -- `openapi/passpod-task.public.yaml` +- `archive/legacy-task/openapi/passpod-task.public.yaml` +- `archive/legacy-task/openapi/README.md` +- `archive/legacy-task/worker-reference/README.md` These consumers are retained as historical legacy material. They do not define the active Passpod v0.1 architecture. ## Provenance -The files in this directory were moved from the repository root schema and example locations using `git mv` so Git history remains traceable. +The receipt schema and examples in this directory were moved from the repository root schema and example locations using `git mv` so Git history remains traceable. + +The OpenAPI and worker-reference material in this directory was moved from `openapi/` and `worker-reference/` using `git mv` to preserve the history of the legacy transport family. diff --git a/openapi/README.md b/archive/legacy-task/openapi/README.md similarity index 89% rename from openapi/README.md rename to archive/legacy-task/openapi/README.md index 4ace64b..22b5da8 100644 --- a/openapi/README.md +++ b/archive/legacy-task/openapi/README.md @@ -1,6 +1,6 @@ # OpenAPI Reference -`openapi/passpod-task.public.yaml` is a public reference shape for Passpod TASK +`passpod-task.public.yaml` is a public reference shape for Passpod TASK Core. It documents draft endpoints for spec discovery, public demo receipt validation, and receipt lookup response shape. diff --git a/openapi/passpod-task.public.yaml b/archive/legacy-task/openapi/passpod-task.public.yaml similarity index 100% rename from openapi/passpod-task.public.yaml rename to archive/legacy-task/openapi/passpod-task.public.yaml diff --git a/worker-reference/README.md b/archive/legacy-task/worker-reference/README.md similarity index 100% rename from worker-reference/README.md rename to archive/legacy-task/worker-reference/README.md diff --git a/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md b/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md index 81346d4..c506435 100644 --- a/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md +++ b/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md @@ -1,6 +1,6 @@ # Canonical Repository Migration Map -Post-archival note: receipt-era schema and example paths quoted in this migration map describe repository state and dependencies observed when the map was written. The legacy receipt family now lives under `archive/legacy-task/`; any former active paths retained below are historical dependency evidence, not active Passpod v0.1 requirements. +Post-archival note: receipt-era schema, receipt example, OpenAPI, and worker-reference paths quoted in this migration map describe repository state and dependencies observed when the map was written. The legacy receipt and transport families now live under `archive/legacy-task/`; any former active paths retained below are historical dependency evidence, not active Passpod v0.1 requirements. ## 1. Executive Summary diff --git a/docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md b/docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md index f362cac..24c28ed 100644 --- a/docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md +++ b/docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md @@ -1,5 +1,7 @@ # OpenAPI Transport Material Decision +Post-archival note: the OpenAPI and worker-reference assets evaluated in this decision have since been moved to `archive/legacy-task/openapi/` and `archive/legacy-task/worker-reference/`. Original paths retained below describe the audited pre-archival locations and are not active Passpod v0.1 paths. + ## 1. Executive Summary This audit reviewed the remaining OpenAPI, worker-reference, API documentation, and transport-oriented material after the Passpod v0.1 specification, schemas, fixtures, validator, SDK, CLI, README, quickstart, gate, CI, and legacy receipt archive were completed. diff --git a/docs/PASSPOD-RESET-AUDIT.md b/docs/PASSPOD-RESET-AUDIT.md index f3a167f..635510d 100644 --- a/docs/PASSPOD-RESET-AUDIT.md +++ b/docs/PASSPOD-RESET-AUDIT.md @@ -6,7 +6,7 @@ Branch observed: `main` Remote observed: `https://github.com/edidx/passpod-task.git` Audit mode: read-only audit plus this single new report file -Post-archival note: legacy receipt schema and receipt example paths referenced by their former active locations in this historical audit have since been moved to `archive/legacy-task/`. Those former paths remain in this report as observations of repository state at audit time, not active Passpod v0.1 requirements. +Post-archival note: legacy receipt schema, receipt example, OpenAPI, and worker-reference paths referenced by their former active locations in this historical audit have since been moved to `archive/legacy-task/`. Those former paths remain in this report as observations of repository state at audit time, not active Passpod v0.1 requirements. ## 1. Executive summary From 8ab431d7c35131db1354b763d643e7c853092255 Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 03:57:51 +0800 Subject: [PATCH 11/18] Audit root documents and package surfaces --- docs/ROOT_PACKAGE_SURFACE_MIGRATION_AUDIT.md | 365 +++++++++++++++++++ 1 file changed, 365 insertions(+) create mode 100644 docs/ROOT_PACKAGE_SURFACE_MIGRATION_AUDIT.md diff --git a/docs/ROOT_PACKAGE_SURFACE_MIGRATION_AUDIT.md b/docs/ROOT_PACKAGE_SURFACE_MIGRATION_AUDIT.md new file mode 100644 index 0000000..515437e --- /dev/null +++ b/docs/ROOT_PACKAGE_SURFACE_MIGRATION_AUDIT.md @@ -0,0 +1,365 @@ +# Root Package Surface Migration Audit + +## 1. Executive Summary + +This audit reviewed the remaining root-level documents, package surfaces, tooling surfaces, release metadata, governance files, and supporting repository files after the Passpod v0.1 reset and the legacy receipt/OpenAPI archives. + +Baseline was clean: + +```text +git status --short +``` + +returned no output, and: + +```text +git log -12 --oneline +``` + +showed `e8b5f41 Archive legacy OpenAPI and worker reference material` as the latest commit. + +Key findings: + +- The repository is currently best treated as a combined specification and reference Python SDK repository. +- There is no tracked JavaScript validator, JavaScript CLI, `package.json`, `package-lock.json`, npm bin entry, package script, or npm publication surface. +- Python packaging metadata is intentionally absent. The Python SDK/CLI is repository-local and exercised through `python3 -m passpod.cli` and unit tests. +- `requirements.txt` is still required for `jsonschema`, which is used by the canonical semantic validator and tests. +- The most active legacy confusion now sits in root and support documentation: `SPEC.md`, `LAUNCH_READINESS.md`, `ROADMAP.md`, `ADOPTION.md`, `COMMERCIAL_BOUNDARY.md`, `PILOT_ACCESS.md`, `VERSIONING.md`, `FUNDING_USE.md`, `cli/README.md`, `validator/README.md`, and several noncanonical docs. +- The highest-risk next cleanup is not package metadata. It is the old TASK specification and launch-family documents that still present receipt/TASK/Hub concepts as public doctrine. + +Recommended next bounded pass: + +```text +Archive legacy SPEC and launch-readiness document family +``` + +## 2. Audit Scope + +Audited tracked assets included: + +- root documents: `SPEC.md`, `CHANGELOG.md`, `VERSIONING.md`, `GOVERNANCE.md`, `ADOPTION.md`, `CONTRIBUTING.md`, `SECURITY.md`, `LICENSE`, `LAUNCH_READINESS.md`, `PILOT_ACCESS.md`, `ROADMAP.md`, `COMMERCIAL_BOUNDARY.md`, `FUNDING_USE.md`, `CODE_OF_CONDUCT.md`, `README.md`; +- package/dependency surfaces: `requirements.txt`, absence of `package.json`, `package-lock.json`, `pyproject.toml`, `setup.py`, `setup.cfg`, Makefile, tox config, and nox config; +- Python implementation: `passpod/`, `validator/semantic_validator.py`, canonical tests; +- documentation-only CLI and validator surfaces: `cli/README.md`, `validator/README.md`; +- tools: `tools/check-public-task-repo.sh`, `tools/validate-receipts.py`, `tools/pilot-readiness.py`; +- GitHub surfaces: `.github/CODEOWNERS`, `.github/PULL_REQUEST_TEMPLATE.md`, `.github/workflows/validate.yml`; +- noncanonical docs under `docs/`; +- historical archive under `archive/legacy-task/`. + +Local empty directories were observed under `src/`, `spec/`, `packages/validator/`, and `.github/ISSUE_TEMPLATE/`. They contain no tracked files and are not treated as repository assets in this audit. + +## 3. Canonical Baseline + +Canonical active assets: + +| Asset | Classification | Evidence | +|---|---|---| +| `README.md` | KEEP - Canonical | Active public entry point; legacy material is isolated in the legacy section. | +| `docs/QUICKSTART.md` | KEEP - Canonical | Current developer commands use canonical fixtures, SDK, CLI, tests, and unsupported-behavior boundaries. | +| `docs/STANDARD.md`, `docs/PROTOCOL.md`, `docs/STATE-MODEL.md`, `docs/MESSAGE-MODEL.md`, `docs/PROFILES.md`, `docs/CONFORMANCE.md`, `docs/TERMINOLOGY.md` | KEEP - Canonical | Normative Passpod v0.1 architecture. | +| `schemas/message.schema.json`, `schemas/handshake.schema.json`, `schemas/profile.schema.json` | KEEP - Canonical | Current machine-readable schema set. | +| `examples/valid/`, `examples/invalid/` | KEEP - Canonical | Current valid and invalid fixtures for semantic validation. | +| `validator/semantic_validator.py` | KEEP - Canonical | Active structural and semantic validator. | +| `passpod/` | KEEP - Canonical | Active repository-local Python SDK and CLI package. | +| `tests/` | KEEP - Canonical | Canonical test suite. | +| `tools/check-public-task-repo.sh` | KEEP - Canonical | Active Passpod v0.1 repository gate. | +| `.github/workflows/validate.yml` | KEEP - Canonical | Active CI runs canonical JSON parsing, tests, and gate. | + +The active protocol remains: + +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` + +## 4. Root Document Inventory + +| Path | Classification | Current purpose | Dependencies | Risk | Proposed future action | Predecessor actions | +|---|---|---|---|---|---|---| +| `README.md` | KEEP - Canonical | Public entry and quickstart map with quarantined legacy links. | Gate link audit; public entry. | Medium if legacy links move without updates. | Keep active; update only moved historical links in future archival passes. | Preserve link audit. | +| `SPEC.md` | ARCHIVE WITH LEGACY TASK | Historical TASK Core spec centered on Trust Action Receipt and receipt decisions. | README legacy link; historical docs; archive references. | High confusion risk if kept at root as "SPEC". | Archive intact under legacy TASK material after updating README link. | Link audit and archive README update. | +| `ADOPTION.md` | MIGRATE | Legacy adoption paths for TASK Core, receipt model, OpenAPI, Hub, and Pilot Access Engine. | Historical public surface; no canonical runtime dependency. | High public-positioning confusion. | Migrate useful reader-path concepts to Passpod v0.1 adoption guidance or archive if fully superseded. | Decide public adoption model. | +| `COMMERCIAL_BOUNDARY.md` | DEFER | Legacy commercial boundary and product stack. | README legacy link; governance/commercial claims. | High because commercial claims require human approval. | Rewrite around Passpod Pilot and support boundaries or archive old product-stack material. | Commercial and pilot policy decision. | +| `PILOT_ACCESS.md` | DEFER | Legacy pilot access funnel through Hub/Pilot Access Engine. | README legacy link; security contact overlap. | High business/process ambiguity. | Migrate to Passpod Pilot workflow-fit evaluation if still valid. | Confirm pilot intake and contact policy. | +| `LAUNCH_READINESS.md` | ARCHIVE WITH LEGACY TASK | Historical v0.1.0 launch checklist for TASK Core. | No current README link found; historical audit references. | Medium public confusion if treated as current launch state. | Archive with SPEC/launch family. | Link/reference audit. | +| `ROADMAP.md` | ARCHIVE WITH LEGACY TASK | TASK Core roadmap for receipt gallery, OpenAPI/schema consistency, freeze/revoke examples. | Public root file; historical references. | Medium because it contradicts current architecture direction. | Archive intact or replace later with Passpod v0.1 roadmap. | Strategy approval for any replacement roadmap. | +| `FUNDING_USE.md` | DEFER | Funding narrative for TASK Core, receipt gallery, OpenAPI checks, and public OSS maintenance. | Historical public file; no runtime dependency. | Medium because funding claims are strategy-sensitive. | Rewrite only with funding/public-positioning approval. | Funding strategy decision. | +| `CHANGELOG.md` | MIGRATE | Minimal historical v0.1.0 entry. | No runtime dependency. | Low, but missing reset/archive history. | Migrate changelog in a dedicated release-history pass. | Version/release authority decision. | +| `VERSIONING.md` | MIGRATE | Old receipt-core version ladder. | Historical docs; version search surface. | High semantic conflict with independent Standard/Profile/SDK versions. | Replace with Passpod v0.1 versioning policy after authority is defined. | Version governance decision. | +| `GOVERNANCE.md` | MIGRATE | Minimal stewardship note for TASK Core and Pilot Access. | Gate requires file presence; public governance surface. | Medium because authority terms are obsolete. | Update terminology and authority scope; do not archive without replacement. | Stewardship approval. | +| `CONTRIBUTING.md` | MIGRATE | Contribution boundary; still mentions sanitized receipt examples and scoped-key internals. | Gate requires file presence. | Low to medium. | Retain safety principle; update examples and terminology to v0.1. | Decide contribution categories. | +| `SECURITY.md` | KEEP - Supporting | Minimal security reporting contact. | Gate requires file presence. | Medium unresolved contact question. | Keep; later confirm whether `pilots@passpod.io` remains the security contact. | Security contact decision. | +| `LICENSE` | KEEP - Supporting | MIT license with DIDX copyright. | Gate requires file presence; archived OpenAPI license metadata references repository license. | High if changed without legal approval. | Keep unchanged unless legal authority approves. | Legal approval. | +| `CODE_OF_CONDUCT.md` | KEEP - Supporting | Minimal community conduct note. | Gate requires file presence. | Low. | Keep or expand later. | None. | + +## 5. Governance and Security Documents + +| Path | Classification | Governance/security finding | Recommended action | +|---|---|---|---| +| `GOVERNANCE.md` | MIGRATE | Still says Passpod TASK Core is stewarded by DIDX and pilots are scoped Pilot Access. Governance likely still needed, but subject and scope are obsolete. | Terminology and authority migration, not archive-first. | +| `SECURITY.md` | KEEP - Supporting | Provides a private-reporting instruction and contact. Contact may conflate security and pilot intake. | Keep until a dedicated security contact decision exists. | +| `CONTRIBUTING.md` | MIGRATE | Useful private-data boundary, but contribution examples are receipt-era. | Update to canonical schemas, fixtures, validator, SDK, CLI, and docs. | +| `LICENSE` | KEEP - Supporting | Legal support asset. DIDX copyright is a legal/stewardship question, not a technical migration target. | Keep unchanged. | +| `CODE_OF_CONDUCT.md` | KEEP - Supporting | Generic, not tied to legacy architecture. | Keep. | +| `.github/CODEOWNERS` | KEEP - Supporting | Ownership points to `@edidx`. | Keep unless repository ownership changes. | +| `.github/PULL_REQUEST_TEMPLATE.md` | KEEP - Supporting | Current checklist is aligned to Passpod v0.1 and transport neutrality. | Keep. | + +Open governance questions: + +- Who has final authority over Standard, Protocol, Profile, SDK, and Pilot changes? +- Does DIDX remain the public legal/stewardship label? +- Should `pilots@passpod.io` remain the security contact, or should security reporting be separated from pilot intake? +- Who approves profile proposals and compatibility claims? + +## 6. Version and Release Documents + +| Asset | Classification | Version finding | Conflict or gap | Recommended action | +|---|---|---|---|---| +| `CHANGELOG.md` | MIGRATE | Only contains `v0.1.0` "Initial public draft structure." | Missing Passpod Specification v0.1 freeze, SDK/CLI, schema, gate, CI, and archive history. | Dedicated changelog migration. | +| `VERSIONING.md` | MIGRATE | Defines `v0.1.x`, `v0.2.x`, and `v1.0.0` around public draft/schema refinement/stable receipt core. | Conflicts with architecture where Standard, Protocol, Profile, SDK, schemas, and implementations may version independently. | Replace after version authority is decided. | +| `LAUNCH_READINESS.md` | ARCHIVE WITH LEGACY TASK | Describes v0.1.0 TASK Core launch checklist. | Refers to receipt schema, OpenAPI, public demo receipts, Hub, scoped keys, and signed pilot receipts. | Archive with legacy launch material. | +| `ROADMAP.md` | ARCHIVE WITH LEGACY TASK | Defines old receipt/TASK roadmap. | Does not reflect Passpod Standard, Protocol, SDK, Profiles, Conformance, or Pilot direction. | Archive or replace in a later roadmap pass. | +| Git tags `v0.1.0`, `v0.1.1` | DEFER | Tags exist but local docs do not explain how they map to the frozen Passpod Specification v0.1. | Release authority and tag semantics are unresolved. | Decide release taxonomy before editing tags or release docs. | + +## 7. Package Metadata Inventory + +| Surface | Finding | Classification | Action | +|---|---|---|---| +| `package.json` | Not present. | Not applicable | Do not create without a package strategy. | +| `package-lock.json` | Not present. | Not applicable | Do not create. | +| npm bin entries | None found. | Not applicable | No npm CLI surface exists. | +| npm scripts | None found. | Not applicable | No npm script consumer exists. | +| JavaScript dependencies | None found. | Not applicable | No JavaScript dependency surface exists. | +| `pyproject.toml`, `setup.py`, `setup.cfg` | Not present. | Not applicable | Python publication remains deferred. | +| `requirements.txt` | `jsonschema[format]>=4,<5`. | KEEP - Supporting | Required by validator and CI/test environment. | +| Makefile/tox/nox | Not present. | Not applicable | No release automation surface found. | + +Conclusion: there is no active package metadata to migrate in this pass. The package-surface decision should remain deferred until the repository decides whether it is a specification repository with a reference SDK, a Python package, or a multi-language monorepo. + +## 8. Python Package Surface + +| Asset | Classification | Current purpose | Dependencies | Risk | Proposed action | +|---|---|---|---|---|---| +| `passpod/__init__.py` | KEEP - Canonical | Package-root exports for `Message`, `Handshake`, `Profile`, and `PasspodValidationError`. | Tests and CLI. | Low. | Keep. | +| `passpod/message.py` | KEEP - Canonical | Message value object backed by canonical validator. | `validator.semantic_validator`. | Low. | Keep. | +| `passpod/handshake.py` | KEEP - Canonical | Handshake value object and append/read helpers. | `Message`, canonical validator. | Low. | Keep. | +| `passpod/profile.py` | KEEP - Canonical | Profile value object. | Canonical validator. | Low. | Keep. | +| `passpod/cli.py` | KEEP - Canonical | Local `validate` and `inspect` CLI through `python3 -m passpod.cli`. | SDK classes and tests. | Medium if documentation still points to legacy CLI README. | Keep; update docs later. | +| `passpod/errors.py` | KEEP - Canonical | SDK validation error boundary. | SDK and CLI. | Low. | Keep. | +| `validator/semantic_validator.py` | KEEP - Canonical | Canonical schema and semantic validator. | `jsonschema`, canonical schemas. | Low. | Keep. | +| `requirements.txt` | KEEP - Supporting | Declares `jsonschema[format]>=4,<5`. | CI, tests, semantic validator, legacy receipt validator. | Medium if removed before dependency strategy exists. | Keep. | + +The Python SDK is repository-local only. No publication metadata was found, and no version metadata is present in `passpod/`. + +## 9. JavaScript Validator and CLI Surface + +No tracked JavaScript validator, JavaScript CLI, TypeScript source, npm package metadata, npm scripts, npm lockfile, or JavaScript tests were found. + +| Surface | Finding | Classification | +|---|---|---| +| JavaScript validator | Not present. | Not applicable | +| JavaScript CLI | Not present. | Not applicable | +| `src/` | Local empty untracked directory; no files. | Not a tracked asset | +| `packages/validator/` | Local empty untracked directory; no files. | Not a tracked asset | +| `package.json` | Not present. | Not applicable | + +No asset qualifies as `RETAIN AS ALTERNATIVE IMPLEMENTATION` today because no non-Python implementation exists in tracked files. + +## 10. Tooling Inventory + +| Tool | Classification | Inputs | Outputs | Semantics | Consumers | Risk | Proposed action | +|---|---|---|---|---|---|---|---| +| `tools/check-public-task-repo.sh` | KEEP - Canonical | Canonical docs, schemas, fixtures, SDK/CLI imports, safety patterns. | Pass/fail gate. | Passpod v0.1 repository gate. | CI and PR template. | Low; contains legacy terms only as containment list. | Keep. | +| `tools/validate-receipts.py` | MIGRATE | Archived receipt schema and archived receipt examples. | Receipt validation messages. | Legacy TASK receipt validation plus useful public-safety checks. | Legacy docs; not CI. | Medium: useful checks but legacy semantics. | Extract reusable safety scanning later, then archive original tool. | +| `tools/pilot-readiness.py` | DEFER | Arbitrary receipt JSON path; usage points to archived remote-worker receipt. | Readiness score and Pilot Access messaging. | Legacy receipt production-readiness scoring. | None found in CI/tests. | Medium: business/pilot semantics unresolved. | Defer until Passpod Pilot assessment model is defined. | + +## 11. Dependency and Reference Map + +| Asset or family | Inbound references | Runtime consumers | Test/CI consumers | Public link risk | Dependency conclusion | +|---|---|---|---|---|---| +| `SPEC.md` | README legacy link; historical audit/migration docs. | None. | None. | Medium because root name looks authoritative. | Safe to archive with README link update. | +| `LAUNCH_READINESS.md` | Historical docs and local root visibility. | None. | None. | Medium. | Safe to archive as historical launch material. | +| `ROADMAP.md` | Historical docs and local root visibility. | None. | None. | Medium. | Safe to archive or replace later after strategy decision. | +| `ADOPTION.md` | Historical docs; root visibility. | None. | None. | Medium. | Migrate or archive after adoption model is approved. | +| `PILOT_ACCESS.md` | README legacy link; historical docs. | None. | None. | High because pilot/commercial expectations are external-facing. | Defer pending Pilot policy. | +| `COMMERCIAL_BOUNDARY.md` | README legacy link; historical docs. | None. | None. | High. | Defer pending commercial boundary decision. | +| `CONTRIBUTING.md`, `GOVERNANCE.md`, `SECURITY.md`, `LICENSE`, `CODE_OF_CONDUCT.md` | README support links; gate required files. | None. | Gate checks file presence. | Medium for governance/security only. | Keep/migrate carefully, not archive-first. | +| `requirements.txt` | Quickstart, CI, legacy docs, validator import failure text. | Validator/tests. | CI installs. | Low. | Keep. | +| `cli/README.md` | Historical docs; root directory. | None. | None. | Medium because it contradicts active CLI existence. | Migrate or archive with legacy tool docs. | +| `validator/README.md` | README legacy link; historical docs. | None. | None. | Medium. | Archive or rewrite after legacy receipt validator treatment. | +| `tools/validate-receipts.py` | Legacy docs and archive README. | Manual only. | None. | Low to medium. | Migrate useful scanning, then archive. | +| `tools/pilot-readiness.py` | Archive README; usage only. | Manual only. | None. | Medium. | Defer. | + +## 12. Legacy Terminology Findings + +Active contamination found: + +- `SPEC.md`: TASK Core, Sensitive Action Control, Trust Action Receipt, receipt decisions, Hub, Control Packs, Pilot Access Engine. +- `LAUNCH_READINESS.md`: public demo receipts, Hub, scoped keys, TASK Core, signed pilot receipts. +- `ROADMAP.md`: TASK Core, receipt gallery, freeze/revoke examples, OpenAPI/schema drift. +- `ADOPTION.md`: TASK Core, Trust Action Receipt, Hub, Pilot Access Engine. +- `COMMERCIAL_BOUNDARY.md`: TASK Core -> Hub -> Control Packs -> Pilot Access stack. +- `PILOT_ACCESS.md`: TASK Core, Trust Action Receipt, Hub, Pilot Access Engine. +- `FUNDING_USE.md`: TASK Core, receipts, OpenAPI references, allow/deny/freeze/revoke. +- `VERSIONING.md`: stable receipt core. +- `cli/README.md`: says no standalone CLI exists and points to legacy receipt validator. +- `validator/README.md`: legacy receipt validator, Hub, Pilot Access Engine. +- `docs/glossary.md`, `docs/receipt-lifecycle.md`, `docs/production-checklist.md`, `docs/public-vs-pilot.md`, `docs/security-model.md`, `docs/standardization-roadmap.md`: legacy receipt/TASK/Pilot material. + +Historical context: + +- `README.md` legacy section. +- `docs/TERMINOLOGY.md` archived terminology section. +- `archive/legacy-task/`. +- Audit and migration reports. + +Legitimate generic use: + +- `allow` as ordinary English in README. +- `receipt` inside explicit legacy/archive contexts. +- `evidence`, `version`, and `profile` in canonical docs and schemas. + +## 13. Versioning Conflicts + +Conflicts and gaps: + +- `VERSIONING.md` defines a receipt-core ladder but does not govern Standard, Protocol, Message Model, Profile, SDK, CLI, schema, or conformance versioning. +- `CHANGELOG.md` does not mention the frozen Passpod Specification v0.1 or subsequent implementation/archive milestones. +- Git tags `v0.1.0` and `v0.1.1` exist, but local docs do not define whether they map to repository releases, specification versions, package versions, or legacy receipt releases. +- Canonical schemas intentionally do not prescribe version syntax. +- Profiles intentionally evolve independently and do not prescribe version syntax. +- The Python SDK has no package/distribution version metadata. +- Archived OpenAPI has `0.1.0-draft`, which is a legacy API version and should not be reused as the Passpod core version. + +Missing authority: + +- Release authority for specification versions. +- Version authority for SDK/CLI. +- Profile version governance. +- Compatibility policy for schema evolution. +- Changelog scope and tag policy. + +## 14. Governance Questions + +Unresolved questions: + +- Should the repository remain under DIDX stewardship language, and how should that be expressed for Passpod v0.1? +- Who approves normative Standard and Protocol changes? +- Who approves Profile lifecycle transitions? +- Who owns SDK and CLI releases? +- Is Passpod Pilot a governance process, a commercial process, or both? +- Should security reports go to `pilots@passpod.io` or a dedicated security contact? +- What compatibility promises are made for schemas, fixtures, SDK, and CLI? +- Are legacy root documents public history, or should root only expose active documents plus archive links? + +This audit does not invent answers. + +## 15. Recommended Repository Model + +Recommended near-term model: + +```text +combined specification and reference Python SDK repository +``` + +Rationale: + +- The canonical docs, schemas, fixtures, validator, SDK, CLI, tests, gate, and CI already live together. +- There is no active package publication surface. +- There is no alternative language implementation. +- The active quickstart is local-repository based, not package-install based. +- The repository still benefits from keeping implementation tests near the frozen specification while v0.1 semantics stabilize. + +Conceptual future structure: + +- Normative specifications: `docs/STANDARD.md`, `docs/PROTOCOL.md`, state/message/profile/conformance/terminology docs. +- Developer documentation: `README.md`, `docs/QUICKSTART.md`, future SDK/CLI docs. +- Active Python implementation: `passpod/`, `validator/semantic_validator.py`, `tests/`. +- Optional future alternative implementations: separate explicitly named implementation directories only after conformance criteria exist. +- Package metadata: defer until publication strategy exists. +- Release/version documents: migrate after version authority is assigned. +- Tools: keep canonical gate; archive or migrate receipt-era utilities separately. +- Historical archive: `archive/legacy-task/` plus future legacy document families. + +## 16. Classification by Asset + +Counts below group closely related directories/families where audited as one surface. + +| Classification | Count | Assets | +|---|---:|---| +| KEEP - Canonical | 11 | `README.md`, `docs/QUICKSTART.md`, normative docs family, canonical schemas, `examples/valid/`, `examples/invalid/`, `validator/semantic_validator.py`, `passpod/`, `tests/`, `tools/check-public-task-repo.sh`, `.github/workflows/validate.yml` | +| KEEP - Supporting | 9 | `LICENSE`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, `requirements.txt`, `.github/CODEOWNERS`, `.github/PULL_REQUEST_TEMPLATE.md`, `docs/SPECIFICATION_FREEZE_REPORT.md`, `docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md`, `docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md` | +| MIGRATE | 13 | `CHANGELOG.md`, `VERSIONING.md`, `GOVERNANCE.md`, `ADOPTION.md`, `CONTRIBUTING.md`, `cli/README.md`, `validator/README.md`, `tools/validate-receipts.py`, `docs/glossary.md`, `docs/non-goals.md`, `docs/public-vs-pilot.md`, `docs/security-model.md`, `docs/threat-model.md` | +| ARCHIVE WITH LEGACY TASK | 7 | `SPEC.md`, `LAUNCH_READINESS.md`, `ROADMAP.md`, `examples/README.md`, `docs/receipt-lifecycle.md`, `docs/production-checklist.md`, archived receipt/OpenAPI/worker family already under `archive/legacy-task/` | +| RETAIN AS ALTERNATIVE IMPLEMENTATION | 0 | None found | +| DEFER | 4 | `PILOT_ACCESS.md`, `COMMERCIAL_BOUNDARY.md`, `FUNDING_USE.md`, `tools/pilot-readiness.py` | +| DELETE-CANDIDATE | 0 | None | + +## 17. Recommended Migration Sequence + +1. Archive legacy SPEC and launch-readiness document family. + + Scope: move `SPEC.md`, `LAUNCH_READINESS.md`, `ROADMAP.md`, and tightly coupled receipt/TASK lifecycle/checklist docs into `archive/legacy-task/` while updating only direct links. + + Stop/go checks: tests pass, gate passes, README links resolve, no canonical docs change, no root `SPEC.md` ambiguity remains. + +2. Migrate governance, security, and contribution documents to Passpod v0.1. + + Scope: update `GOVERNANCE.md`, `CONTRIBUTING.md`, and security contact wording after authority decisions. + + Stop/go checks: gate passes, legacy terms appear only in archive/migration contexts, governance questions are answered by maintainers. + +3. Decide Passpod Pilot and commercial boundary language. + + Scope: migrate or archive `PILOT_ACCESS.md`, `COMMERCIAL_BOUNDARY.md`, relevant public/pilot docs, and `tools/pilot-readiness.py`. + + Stop/go checks: no Pilot Access Engine claims remain active; pilot contact and commercial claims are approved. + +4. Migrate release and version documents. + + Scope: replace `VERSIONING.md` and update `CHANGELOG.md` around specification, schema, SDK, CLI, profile, and repository release tracks. + + Stop/go checks: version authority is documented; no universal version number is invented without support. + +5. Archive or migrate legacy receipt validator documentation and utility. + + Scope: extract any reusable public-safety scanning from `tools/validate-receipts.py`, then archive the receipt-specific validator and docs. + + Stop/go checks: canonical gate still covers private-data leakage; canonical tests and CI remain green. + +6. Decide package/publication surface. + + Scope: determine whether to add Python packaging metadata or keep repository-local usage. + + Stop/go checks: package strategy is approved; no npm surface is introduced without an implementation. + +## 18. Explicit Non-actions + +This pass did not: + +- modify existing files; +- move or rename files; +- archive or delete files; +- update package metadata; +- rewrite governance; +- create packaging; +- create scripts; +- change tests; +- change CI; +- change the gate; +- change canonical code; +- commit; +- push. + +## 19. Final Recommendation + +The immediate package-surface audit does not support a JavaScript archival pass because no tracked JavaScript implementation or npm package surface exists. + +The next highest-value, dependency-safe cleanup is to remove ambiguity around the old root `SPEC.md` and related TASK launch documents by archiving them as historical legacy material. + +Recommended next bounded pass: + +```text +Archive legacy SPEC and launch-readiness document family +``` + +Do not begin that pass from this report. From d3e9b54ad35163b9297e4cdcc00d7b41612eb321 Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 04:04:43 +0800 Subject: [PATCH 12/18] Archive legacy specification and launch documents --- README.md | 2 +- archive/legacy-task/README.md | 24 ++++++++++++++++--- .../legacy-task/docs/LAUNCH_READINESS.md | 0 .../legacy-task/docs/ROADMAP.md | 0 SPEC.md => archive/legacy-task/docs/SPEC.md | 2 +- docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md | 2 +- docs/PASSPOD-RESET-AUDIT.md | 2 +- docs/ROOT_PACKAGE_SURFACE_MIGRATION_AUDIT.md | 2 ++ 8 files changed, 27 insertions(+), 7 deletions(-) rename LAUNCH_READINESS.md => archive/legacy-task/docs/LAUNCH_READINESS.md (100%) rename ROADMAP.md => archive/legacy-task/docs/ROADMAP.md (100%) rename SPEC.md => archive/legacy-task/docs/SPEC.md (98%) diff --git a/README.md b/README.md index 517f2cd..98d8756 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,7 @@ These terms are outside the active Passpod v0.1 architecture. They are preserved Historical migration references: -- [Legacy specification](SPEC.md) +- [Legacy specification](archive/legacy-task/docs/SPEC.md) - [Legacy receipt schema](archive/legacy-task/schemas/trust-action-receipt.schema.json) - [Legacy OpenAPI reference](archive/legacy-task/openapi/passpod-task.public.yaml) - [Legacy examples guide](examples/README.md) diff --git a/archive/legacy-task/README.md b/archive/legacy-task/README.md index 3e36338..d3f1bb5 100644 --- a/archive/legacy-task/README.md +++ b/archive/legacy-task/README.md @@ -8,12 +8,15 @@ This material is not canonical Passpod v0.1. Trust Action Receipts are not the p ## Historical Context -The archived schema and examples come from the earlier TASK receipt family. They describe historical Trust Action Receipt concepts, demo receipt examples, and receipt-era tooling inputs. +The archived schema, examples, specification, roadmap, and launch-readiness documents come from the earlier TASK receipt family. They describe historical Trust Action Receipt concepts, demo receipt examples, receipt-era tooling inputs, and TASK-era launch planning. Passpod v0.1 is defined by the Standard, Handshake Protocol, State Model, Message Model, Profile model, Conformance model, canonical schemas, canonical fixtures, semantic validator, SDK core, and CLI. ## Archived Contents +- [docs/SPEC.md](docs/SPEC.md) +- [docs/LAUNCH_READINESS.md](docs/LAUNCH_READINESS.md) +- [docs/ROADMAP.md](docs/ROADMAP.md) - [schemas/trust-action-receipt.schema.json](schemas/trust-action-receipt.schema.json) - [examples/remote-worker.receipt.json](examples/remote-worker.receipt.json) - [examples/refund-review.receipt.json](examples/refund-review.receipt.json) @@ -35,6 +38,15 @@ Active fixtures are under: - [../../examples/valid/](../../examples/valid/) - [../../examples/invalid/](../../examples/invalid/) +Active normative documents are under: + +- [../../docs/](../../docs/) + +Current developer guidance is: + +- [../../README.md](../../README.md) +- [../../docs/QUICKSTART.md](../../docs/QUICKSTART.md) + ## Usage Warning Archived examples must not be used to infer current protocol semantics. They are legacy receipt examples, not Passpod v0.1 messages, handshakes, profiles, or conformance fixtures. @@ -45,15 +57,19 @@ The archived OpenAPI document describes the previous receipt-oriented HTTP servi Future HTTP binding work must be designed separately from the core protocol. The archival decision is documented in [../../docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md](../../docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md). +The archived specification, roadmap, and launch-readiness documents describe the previous TASK-era specification and launch model. They are retained for provenance, decision history, and migration analysis. They are not current normative, roadmap, release, or launch-readiness material for Passpod v0.1. + ## Legacy Consumers -The following legacy consumers may still mention or load archived receipt-era material: +The following legacy consumers may still mention or load archived receipt-era or TASK-era material: - `tools/validate-receipts.py` - `tools/pilot-readiness.py` - `validator/README.md` - `examples/README.md` -- `SPEC.md` +- `archive/legacy-task/docs/SPEC.md` +- `archive/legacy-task/docs/LAUNCH_READINESS.md` +- `archive/legacy-task/docs/ROADMAP.md` - `archive/legacy-task/openapi/passpod-task.public.yaml` - `archive/legacy-task/openapi/README.md` - `archive/legacy-task/worker-reference/README.md` @@ -65,3 +81,5 @@ These consumers are retained as historical legacy material. They do not define t The receipt schema and examples in this directory were moved from the repository root schema and example locations using `git mv` so Git history remains traceable. The OpenAPI and worker-reference material in this directory was moved from `openapi/` and `worker-reference/` using `git mv` to preserve the history of the legacy transport family. + +The specification, launch-readiness, and roadmap documents in `archive/legacy-task/docs/` were moved from the repository root using `git mv` to preserve the history of the legacy document family. diff --git a/LAUNCH_READINESS.md b/archive/legacy-task/docs/LAUNCH_READINESS.md similarity index 100% rename from LAUNCH_READINESS.md rename to archive/legacy-task/docs/LAUNCH_READINESS.md diff --git a/ROADMAP.md b/archive/legacy-task/docs/ROADMAP.md similarity index 100% rename from ROADMAP.md rename to archive/legacy-task/docs/ROADMAP.md diff --git a/SPEC.md b/archive/legacy-task/docs/SPEC.md similarity index 98% rename from SPEC.md rename to archive/legacy-task/docs/SPEC.md index 2fa82da..9d27914 100644 --- a/SPEC.md +++ b/archive/legacy-task/docs/SPEC.md @@ -26,7 +26,7 @@ were considered. A Trust Action Receipt is the portable output of a TASK decision. In this public v0.1 draft, a receipt is a JSON object that can be validated -against `archive/legacy-task/schemas/trust-action-receipt.schema.json`. A schema-valid public +against `../schemas/trust-action-receipt.schema.json`. A schema-valid public receipt means the object follows the draft shape. It does not mean the receipt was issued by a production service, signed by a production issuer, stored by a hosted verification service, or accepted for a real workflow. diff --git a/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md b/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md index c506435..a7cafb7 100644 --- a/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md +++ b/docs/CANONICAL_REPOSITORY_MIGRATION_MAP.md @@ -1,6 +1,6 @@ # Canonical Repository Migration Map -Post-archival note: receipt-era schema, receipt example, OpenAPI, and worker-reference paths quoted in this migration map describe repository state and dependencies observed when the map was written. The legacy receipt and transport families now live under `archive/legacy-task/`; any former active paths retained below are historical dependency evidence, not active Passpod v0.1 requirements. +Post-archival note: receipt-era schema, receipt example, OpenAPI, worker-reference, legacy specification, launch-readiness, and roadmap paths quoted in this migration map describe repository state and dependencies observed when the map was written. The legacy receipt, transport, and document families now live under `archive/legacy-task/`; any former active paths retained below are historical dependency evidence, not active Passpod v0.1 requirements. ## 1. Executive Summary diff --git a/docs/PASSPOD-RESET-AUDIT.md b/docs/PASSPOD-RESET-AUDIT.md index 635510d..2276e68 100644 --- a/docs/PASSPOD-RESET-AUDIT.md +++ b/docs/PASSPOD-RESET-AUDIT.md @@ -6,7 +6,7 @@ Branch observed: `main` Remote observed: `https://github.com/edidx/passpod-task.git` Audit mode: read-only audit plus this single new report file -Post-archival note: legacy receipt schema, receipt example, OpenAPI, and worker-reference paths referenced by their former active locations in this historical audit have since been moved to `archive/legacy-task/`. Those former paths remain in this report as observations of repository state at audit time, not active Passpod v0.1 requirements. +Post-archival note: legacy receipt schema, receipt example, OpenAPI, worker-reference, specification, launch-readiness, and roadmap paths referenced by their former active locations in this historical audit have since been moved to `archive/legacy-task/`. Those former paths remain in this report as observations of repository state at audit time, not active Passpod v0.1 requirements. ## 1. Executive summary diff --git a/docs/ROOT_PACKAGE_SURFACE_MIGRATION_AUDIT.md b/docs/ROOT_PACKAGE_SURFACE_MIGRATION_AUDIT.md index 515437e..d9b4371 100644 --- a/docs/ROOT_PACKAGE_SURFACE_MIGRATION_AUDIT.md +++ b/docs/ROOT_PACKAGE_SURFACE_MIGRATION_AUDIT.md @@ -1,5 +1,7 @@ # Root Package Surface Migration Audit +Post-archival note: the legacy `SPEC.md`, `LAUNCH_READINESS.md`, and `ROADMAP.md` files evaluated in this audit have since been moved to `archive/legacy-task/docs/`. Original root paths retained below describe audited pre-archival locations and dependencies, not active Passpod v0.1 authority. + ## 1. Executive Summary This audit reviewed the remaining root-level documents, package surfaces, tooling surfaces, release metadata, governance files, and supporting repository files after the Passpod v0.1 reset and the legacy receipt/OpenAPI archives. From 68daee8341e6e6d8119bb70caec0bbdc3d0f997b Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 04:09:45 +0800 Subject: [PATCH 13/18] Migrate governance and contribution docs to Passpod v0.1 --- CODE_OF_CONDUCT.md | 4 ++ CONTRIBUTING.md | 86 +++++++++++++++++++++++++++++++++- GOVERNANCE.md | 114 ++++++++++++++++++++++++++++++++++++++++++++- SECURITY.md | 51 +++++++++++++++++++- 4 files changed, 250 insertions(+), 5 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 366a60a..1d04f71 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,7 @@ # Code of Conduct +This applies to Passpod as a specification and reference implementation repository. + Be respectful, practical, and security-conscious. + +This document does not assign an enforcement contact or authority. That path remains a project-governance question. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f74af16..e720f9c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,87 @@ # Contributing -Useful contributions: schema feedback, sanitized receipt examples, security model comments, and compatibility notes. +Passpod is a specification repository with a reference Python SDK, semantic validator, CLI, schemas, fixtures, tests, and migration archive. -Do not submit private customer data, production keys, buyer-specific workflows, or scoped key internals. +Start with: + +- [README.md](README.md) +- [docs/QUICKSTART.md](docs/QUICKSTART.md) +- [docs/STANDARD.md](docs/STANDARD.md) +- [docs/PROTOCOL.md](docs/PROTOCOL.md) +- [docs/STATE-MODEL.md](docs/STATE-MODEL.md) +- [docs/MESSAGE-MODEL.md](docs/MESSAGE-MODEL.md) +- [docs/PROFILES.md](docs/PROFILES.md) +- [docs/CONFORMANCE.md](docs/CONFORMANCE.md) +- [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md) +- [.github/PULL_REQUEST_TEMPLATE.md](.github/PULL_REQUEST_TEMPLATE.md) + +## Local Validation + +Run these commands from the repository root: + +```bash +PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests +bash tools/check-public-task-repo.sh +``` + +The script `tools/check-public-task-repo.sh` keeps its historical filename. Treat it as the Passpod v0.1 repository gate. + +## Contribution Boundaries + +Contributions must preserve: + +- `PROPOSE -> CHALLENGE -> AGREE -> CLOSE`; +- transport neutrality; +- append-only history; +- immutable accepted messages; +- terminal closure; +- Profile non-redefinition; +- validator error-code stability where applicable; +- SDK and CLI behavior as consumers of semantics, not sources of semantics. + +Keep changes bounded. Include tests for behavior changes. Do not mix unrelated refactors with normative architecture changes. + +Do not add unsupported transports, HTTP APIs, persistence, signatures, cryptography, identity verification, authorization, production infrastructure, or published package claims unless a future approved pass explicitly scopes that work. + +## Artifact Guidance + +Normative documents: changes require explicit architectural review and must not be mixed casually with implementation refactors. + +Schemas: express frozen concepts without inventing semantics. + +Fixtures: valid and invalid fixtures must state the behavior they demonstrate. + +Validator: deterministic error codes must remain stable unless intentionally versioned. + +SDK: consume validator semantics and preserve defensive-copy and append-only guarantees. + +CLI: remain a thin local interface over the SDK and validator. + +Archive: historical files must not be rewritten as current Passpod v0.1 material. + +## Pull Requests + +Use the current [pull request template](.github/PULL_REQUEST_TEMPLATE.md). + +Pull requests should have: + +- bounded scope; +- no unrelated changes; +- exact test results; +- accurate claims; +- no secrets or private data; +- verified links and commands. + +## Python Assumptions + +Use Python 3. + +The SDK and CLI use standard library interfaces. Validation tooling and CI use dependencies installed from [requirements.txt](requirements.txt) where required. + +CI currently validates on Python 3.12. The repository does not claim PyPI publication or a packaged installation path. + +## Sensitive Data + +Do not submit private customer data, production keys, private keys, tokens, private pilot records, sensitive evidence payloads, or buyer-specific workflows. + +Use synthetic data in fixtures, tests, issues, and pull requests. diff --git a/GOVERNANCE.md b/GOVERNANCE.md index b29e402..364cd43 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -1,5 +1,115 @@ # Governance -Passpod TASK Core is currently stewarded by DIDX. +This document describes governance boundaries for the current Passpod repository. -Production pilots are handled separately through scoped Pilot Access. +The repository is a combined Passpod specification repository with a reference Python SDK. It contains normative architecture documents, canonical schemas and fixtures, a semantic validator, SDK value objects, a local CLI, tests, supporting documentation, and migration archive material. + +## Governance Scope + +Governance applies to: + +- the Passpod Standard and normative documents; +- the Handshake Protocol; +- the State Model; +- the Message Model; +- the Profile model; +- the Conformance model; +- canonical schemas and fixtures; +- the reference Python SDK; +- the semantic validator; +- the CLI; +- supporting documentation. + +The Standard remains the semantic authority for Passpod. The SDK, CLI, validator, schemas, fixtures, tests, CI, and repository gate consume the frozen semantics; they do not replace them. + +## Change Categories + +Changes may fall into more than one category: + +- normative; +- implementation; +- documentation; +- Profile; +- archive or migration; +- security-sensitive. + +The category determines the review care required. This document does not create a separate RFC process, standards body, voting procedure, or certification program. + +## Normative Changes + +Normative changes alter the meaning of the Passpod architecture. + +Normative changes include changes to the meaning of: + +- `PROPOSE`; +- `CHALLENGE`; +- `AGREE`; +- `CLOSE`; +- append-only history; +- immutable accepted messages; +- terminal closure; +- Profiles; +- core conformance. + +Normative changes require explicit project-governance approval before merge. The exact final authority for normative approval is not fully defined in this repository. + +Breaking normative changes require a future specification version. They must not be introduced silently through SDK behavior, validator behavior, CLI behavior, schema shape, tests, documentation examples, or profile language. + +## Implementation Changes + +Implementation changes include changes to: + +- SDK ergonomics; +- CLI behavior; +- validator implementation; +- tests; +- tooling; +- CI; +- documentation presentation. + +Implementation changes must remain conformant with the frozen normative documents. They may improve local developer experience, validation behavior, or code structure, but they must not redefine the protocol. + +## Profile Changes + +Profiles specialize Passpod for a domain or workflow. Profiles must not redefine: + +- `PROPOSE`; +- `CHALLENGE`; +- `AGREE`; +- `CLOSE`; +- append-only history; +- immutable accepted messages; +- Standard semantics; +- Protocol semantics. + +Profile approval authority is unresolved. A profile may be proposed or reviewed for semantic compatibility, but this document does not assign final profile approval to any committee, standards body, release manager, or other new governance body. + +## Compatibility + +Passpod Specification v0.1 is conceptually frozen. + +Implementation changes must not silently redefine the protocol. Profile compatibility may evolve independently, but no universal version syntax is defined in this document. + +## Historical Archive + +The `archive/legacy-task/` directory is retained for provenance, migration analysis, and decision history. + +Archived files are non-canonical. They must not be treated as sources of active protocol meaning, release authority, security authority, or profile authority. + +## Authority Boundaries + +Repository ownership evidence is limited. The current repository includes `.github/CODEOWNERS`, which identifies repository review ownership, and legal/supporting files that should not be expanded into broader governance claims without explicit approval. + +Unresolved authority questions include: + +- Standard stewardship; +- normative-change approval; +- Profile approval; +- SDK release authority; +- CLI release authority; +- security reporting contact; +- code-of-conduct enforcement contact; +- pilot approval; +- archive authority. + +Until those questions are resolved, contributors should make bounded changes, preserve the active architecture, and avoid claims of formal standards-body recognition, certification, production readiness, or community governance. diff --git a/SECURITY.md b/SECURITY.md index b4c17ac..1566bae 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,4 +2,53 @@ Please report security concerns privately. -Contact: pilots@passpod.io +The current evidence-backed contact is `pilots@passpod.io`. Whether this remains the long-term security contact or is replaced by a dedicated security-reporting path is unresolved. + +If the hosting platform provides a private security-reporting mechanism for this repository, use that private mechanism. Otherwise, use the contact above. Do not post sensitive details publicly. + +## Security Scope + +Security reports may concern: + +- validator bypasses; +- invalid lifecycle acceptance; +- parent-reference failures; +- duplicate identity handling; +- mutation or defensive-copy failures; +- CLI data exposure; +- secret or private-data leakage; +- unsafe network behavior if transport work is added later; +- dependency vulnerabilities; +- archive material accidentally becoming active. + +## Current Boundaries + +The current reference implementation does not include: + +- transport; +- HTTP APIs; +- persistence; +- signatures; +- cryptography; +- identity verification; +- authorization; +- production infrastructure. + +Do not assume those unsupported layers are secured by this repository. + +## Sensitive Data + +Do not submit: + +- real secrets; +- private keys; +- tokens; +- private pilot records; +- customer data; +- sensitive evidence payloads. + +Use synthetic reproduction data wherever possible. Do not email sensitive secrets. + +## Security Claims + +This repository does not claim production-grade security, cryptographic proof, key management, enterprise deployment readiness, formal audit, certification, penetration testing, or guaranteed isolation. From 61a4a4d450868eb71c6ee50618c965c19c407d7f Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 04:14:32 +0800 Subject: [PATCH 14/18] Migrate changelog and versioning to Passpod v0.1 --- CHANGELOG.md | 48 +++++++++++++++++++- VERSIONING.md | 118 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 161 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 555331d..df2fbac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,49 @@ # Changelog -## v0.1.0 +## Unreleased -Initial public draft structure. +### Added + +- Passpod Standard, Handshake Protocol, State Model, Message Model, Profiles model, Conformance model, and Terminology documents for Passpod Specification v0.1. +- Specification freeze report documenting internal consistency of the canonical v0.1 architecture. +- Canonical machine-readable schemas for messages, handshakes, and profiles. +- Valid and invalid fixtures for the canonical handshake and profile model. +- Semantic validator for structural and protocol-level validation. +- Reference Python SDK value objects for messages, handshakes, profiles, and validation errors. +- SDK fixture round-trip coverage for canonical examples. +- CLI `validate` and `inspect` commands. +- Developer quickstart for local tests, validation, inspection, and SDK usage. +- Passpod v0.1 repository gate. +- Canonical CI validation for JSON parsing, unit tests, and the repository gate. + +### Changed + +- README migrated to present Passpod v0.1 as a transport-neutral specification and handshake protocol. +- Repository positioning migrated to a combined Passpod specification repository with a reference Python SDK. +- CI and pull request checks migrated from TASK-era requirements to Passpod v0.1 architecture checks. +- Governance, security, contribution, and conduct documents migrated to current Passpod v0.1 terminology and authority boundaries. + +### Archived + +- Legacy receipt schema and receipt examples moved into the legacy archive. +- Legacy OpenAPI and worker-reference material moved into the legacy archive. +- Legacy TASK-era specification, roadmap, and launch-readiness documents moved into the legacy archive. + +See [archive/legacy-task/README.md](archive/legacy-task/README.md) for archive context. Archived materials are historical and do not define active Passpod v0.1 compatibility. + +### Security + +- Repository gate preserves checks for secrets, private keys, sensitive local files, and private operational data patterns. +- CLI inspection output is bounded and does not dump full message payloads, evidence references, extensions, sender payloads, or recipient payloads. + +## Historical TASK-Era Tags + +These tags predate the Passpod v0.1 architectural reset. They are retained as repository history and do not represent a Passpod Specification v0.1 release. + +### v0.1.1 + +- Public validation and launch-readiness checkpoint for the earlier TASK Core architecture. + +### v0.1.0 + +- Initial public draft structure. diff --git a/VERSIONING.md b/VERSIONING.md index 2550ee7..d91d1cb 100644 --- a/VERSIONING.md +++ b/VERSIONING.md @@ -1,5 +1,117 @@ # Versioning -v0.1.x = public draft. -v0.2.x = schema refinement. -v1.0.0 = stable receipt core. +## Purpose + +Versioning communicates compatibility across the Passpod specification and its reference implementation. + +The repository is a combined Passpod specification repository with a reference Python SDK. Different layers may evolve independently, and this document does not collapse them into one universal version number. + +## Version Domains + +### Specification Version + +The specification version identifies the normative Passpod architecture and semantics. + +The current conceptual specification is: + +```text +Passpod Specification v0.1 +``` + +Its frozen documents are under `docs/`. This phrase describes the conceptual specification state; it does not imply a Git tag unless such a tag exists. + +### Protocol Version + +A future protocol-version identifier may be needed for message compatibility. + +No separate protocol version representation is currently defined by the canonical documents or schemas. + +### Schema Version + +Canonical schemas currently express the machine-readable v0.1 model. + +Schema changes must preserve compatibility or intentionally version compatibility. This repository does not currently define schema package releases. + +### Profile Version + +Profiles evolve independently from the core specification. + +No active reference Profile is currently implemented, and this document does not define Profile version syntax. + +### SDK and CLI Version + +The reference Python SDK and CLI exist in this repository. + +They are not currently presented as published packages, and this document does not create SDK or CLI package versions. + +### Repository Tags and Releases + +Git tags identify repository snapshots. + +A repository tag does not automatically mean the specification, protocol, schemas, profiles, SDK, CLI, and repository all share the same version number. + +Existing repository tags are historical TASK-era snapshots unless later evidence establishes a different scope. + +## Compatibility Principles + +- Normative semantic changes require an intentional future specification version. +- Implementation changes must not silently redefine frozen semantics. +- Backwards-compatible SDK ergonomics may evolve independently. +- Validator error-code changes may affect consumers and must be deliberate. +- Schemas and fixtures must remain traceable to applicable normative documents. +- Profile compatibility is scoped to each Profile. +- Archived TASK-era versions do not define Passpod v0.1 compatibility. + +This document does not promise permanent backwards compatibility. + +## Breaking Changes + +A breaking change is a change that makes existing conformant material, tooling behavior, or documented compatibility expectations incompatible with the affected version domain. + +Normative breaking changes may include: + +- redefining `PROPOSE`, `CHALLENGE`, `AGREE`, or `CLOSE`; +- changing append-only history semantics; +- changing immutable accepted-message semantics; +- changing terminal closure semantics; +- changing core Profile non-redefinition rules. + +Implementation breaking changes may include: + +- changing required schema structure incompatibly; +- removing stable validator error codes relied on by consumers; +- changing SDK behavior in an incompatible way; +- changing CLI behavior in an incompatible way; +- changing a Profile incompatibly. + +Normative breaking changes affect the meaning of Passpod. Implementation breaking changes affect a concrete artifact such as schemas, SDK, CLI, validator, fixtures, or a Profile. + +## Pre-1.0 Discipline + +The `v0.x` label indicates early evolution, but frozen v0.1 semantics should still be changed deliberately and documented. + +Pre-1.0 status does not remove compatibility obligations. Semantic Versioning may guide future package or SDK releases if those release surfaces are created, but this repository does not currently claim that every layer follows SemVer. + +## Release and Tag Authority + +Authority to approve specification releases, repository tags, SDK or CLI releases, schema compatibility changes, and Profile releases is governed by [GOVERNANCE.md](GOVERNANCE.md). + +Where `GOVERNANCE.md` marks authority unresolved, this document does not resolve it. + +## Archived Versions + +TASK-era receipt, schema, and API versions are retained under [archive/legacy-task/](archive/legacy-task/). + +They are historical and do not participate in active Passpod v0.1 compatibility. + +## Non-goals + +This document does not: + +- create a Git tag; +- publish an SDK package; +- define a release calendar; +- define universal version syntax; +- certify compatibility; +- define Profile governance; +- create an HTTP API version. From 86815b0656be5767dc1e9918dc806e1a2f22a896 Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 04:20:02 +0800 Subject: [PATCH 15/18] Migrate adoption pilot and commercial boundaries --- ADOPTION.md | 103 +++++++++++++++++++++++++++++++++++------ COMMERCIAL_BOUNDARY.md | 76 +++++++++++++++++++----------- FUNDING_USE.md | 74 ++++++++++++++--------------- PILOT_ACCESS.md | 85 +++++++++++++++++++++++++++++----- 4 files changed, 249 insertions(+), 89 deletions(-) diff --git a/ADOPTION.md b/ADOPTION.md index bb598c0..0fedc65 100644 --- a/ADOPTION.md +++ b/ADOPTION.md @@ -1,19 +1,96 @@ -# Adopting Passpod TASK Core +# Adoption -Passpod TASK Core is a public draft standard proposal for Sensitive Action Control. +This document explains how an evaluator, implementer, standards participant, or potential pilot partner can assess Passpod without assuming established adoption. -Vocabulary: Sensitive Action Control, Trust Action Receipt, No receipt, no sensitive action, Passpod TASK Core. +Passpod is a transport-neutral standard and handshake protocol for structured trust negotiation. The canonical flow is: -## Reader paths +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` -- Developer: inspect the schema, examples, OpenAPI reference, and validator to understand the public receipt model. -- Security reviewer: review the demo-vs-production boundary, threat model, and public/private exclusions. -- Pilot buyer: use the public repo to evaluate the standard, then request scoped Passpod Hub access through the Pilot Access Engine. -- Standards/community reader: evaluate Sensitive Action Control, Trust Action Receipt semantics, and Passpod Protocol doctrine without relying on private product internals. +Adoption in this document means evaluation, experimentation, implementation, interoperability exploration, workflow-fit analysis, Profile design, or conformance feedback. It does not imply customers, ecosystem adoption, market traction, production deployment, or formal standards recognition. -## Boundary +## Adoption Paths -This repository proves the public standard and test layer. It does not expose -the full Passpod Hub product, production issuer logic, scoped key generation, -customer workflows, private commercial logic, Sentinel/Ops internals, or an -exit roadmap. +### 1. Read The Specification + +Start with: + +- [README.md](README.md) +- [docs/STANDARD.md](docs/STANDARD.md) +- [docs/PROTOCOL.md](docs/PROTOCOL.md) +- [docs/STATE-MODEL.md](docs/STATE-MODEL.md) +- [docs/MESSAGE-MODEL.md](docs/MESSAGE-MODEL.md) +- [docs/PROFILES.md](docs/PROFILES.md) +- [docs/CONFORMANCE.md](docs/CONFORMANCE.md) + +The Standard remains the semantic authority. The protocol, state model, message model, Profiles model, and conformance model explain how the architecture is interpreted. + +### 2. Run The Reference Implementation + +Use the local reference implementation to inspect the current repository behavior: + +- [docs/QUICKSTART.md](docs/QUICKSTART.md) +- [schemas/](schemas/) +- [examples/valid/](examples/valid/) +- [examples/invalid/](examples/invalid/) +- [validator/semantic_validator.py](validator/semantic_validator.py) +- [passpod/](passpod/) +- [passpod/cli.py](passpod/cli.py) + +The reference implementation is minimal and transport-neutral. It is useful for evaluation, fixtures, SDK behavior, CLI inspection, and validator feedback. It is not a production transport or hosted service. + +### 3. Evaluate A Workflow + +An evaluator may model an existing negotiation as: + +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` + +This can help identify participants, evidence expectations, constraints, agreement boundaries, and terminal outcomes. The repository does not prescribe business outcomes. + +### 4. Explore A Profile Candidate + +Domain-specific roles, evidence expectations, constraints, terminology, workflow guidance, and terminal interpretations belong in Profiles. + +No active Reference Profile is currently implemented. A Profile candidate should preserve the Standard, the Handshake Protocol, append-only history, immutable accepted messages, and terminal closure. + +### 5. Participate In Passpod Pilot + +Passpod Pilot is the controlled evaluation path for workflow fit, handshake modeling, Profile candidate discovery, implementation feedback, evidence expectation discovery, conformance questions, and developer experience feedback. See [PILOT_ACCESS.md](PILOT_ACCESS.md). + +Pilot work does not automatically change the Standard. Any normative change requires intentional architectural review. + +## Adoption Maturity + +Current status: + +- Passpod Specification v0.1 is conceptually frozen. +- A minimal transport-neutral reference implementation exists. +- No production transport binding is included. +- No active Reference Profile is implemented. +- No certification program is defined. +- No conformance certification program exists. +- No guaranteed interoperability is claimed. +- No published package is assumed. +- No adoption metrics are claimed. + +The existing test suite demonstrates repository behavior. It is not evidence of market adoption, production use, pilot acceptance, or standards-body recognition. + +## Unsupported Commitments + +This repository currently does not provide: + +- production SLA; +- hosted service; +- deployment support; +- commercial support commitment; +- certification; +- cryptographic trust; +- identity verification; +- persistence; +- HTTP API; +- formal standards-body process. + +These are not promised future products in this document. diff --git a/COMMERCIAL_BOUNDARY.md b/COMMERCIAL_BOUNDARY.md index c33bd34..65a944d 100644 --- a/COMMERCIAL_BOUNDARY.md +++ b/COMMERCIAL_BOUNDARY.md @@ -1,38 +1,60 @@ # Commercial Boundary -This repository is public proof for Passpod TASK Core. +This document separates the open Passpod specification and reference implementation from possible future commercial activity. -It helps developers and reviewers inspect the public standard/test layer: +It does not define current pricing, service plans, hosted availability, commercial commitments, customers, revenue, partners, or deployment status. -- Trust Action Receipt schema; -- public demo receipts; -- local validator; -- public OpenAPI reference shape; -- basic doctrine for Sensitive Action Control. +## Open Repository Boundary -## Product stack +This repository currently contains: -Passpod TASK Core -> Passpod Hub -> Control Packs -> Pilot Access -> paid pilot / Team / Enterprise. +- normative specification documents; +- canonical schemas; +- valid and invalid fixtures; +- semantic validator; +- reference Python SDK; +- CLI; +- tests; +- governance and developer documentation; +- migration archive material. -- Passpod TASK Core is the public standard/test layer in this repo. -- Passpod Hub is the paid hosted product layer and is not included here. -- Control Packs are AgentTrust and Remote Worker Trust. -- Pilot Access Engine is the scoped access path for authorized hosted access. -- DIDX is the company, legal, and registry anchor. +The repository's rights and conditions are defined by [LICENSE](LICENSE). This document does not add license grants or restrictions. -## Not in this repo +The open repository is sufficient to read the current specification, run the reference implementation, inspect fixtures, and evaluate the canonical handshake model locally. -This repo does not expose: +## Possible Future Commercial Activity -- production issuer logic; -- production signing internals; -- scoped key generation; -- Passpod Hub internals; -- customer workflows; -- private commercial strategy; -- Sentinel/Ops internals; -- exit roadmap. +Possible future commercial services could include: -Public demo receipts are not production-valid receipts. Production-valid -receipts require authorized issuer access through Passpod Hub and the Pilot -Access Engine. +- implementation assistance; +- integration support; +- Profile design assistance; +- pilot facilitation; +- hosted transport bindings; +- managed validation; +- operational support; +- enterprise support. + +These are possibilities, not current offerings. This document does not state prices, plans, availability, service levels, launch dates, or acceptance criteria. + +## Separation From The Standard + +Commercial services must not silently redefine: + +- the Passpod Standard; +- the Handshake Protocol; +- message semantics; +- conformance; +- Profile rules. + +A hosted or commercial implementation is not automatically normative. Paid access is not required for understanding or implementing the open specification. + +## Current Commercial Status + +This repository does not define current pricing, service plans, hosted availability, or commercial commitments. + +It does not claim production deployment, production readiness, active customers, revenue, funding, negotiations, partnerships, grants, investors, or enterprise support. + +## Archived Model + +Archived TASK-era materials described Hub, Pilot Access Engine, scoped-key, and receipt-service concepts. Those concepts are retained for provenance in archive material only and are not part of the current Passpod v0.1 architecture. diff --git a/FUNDING_USE.md b/FUNDING_USE.md index ecea195..4f78c27 100644 --- a/FUNDING_USE.md +++ b/FUNDING_USE.md @@ -1,53 +1,51 @@ -# Funding Use: Codex Open Source Fund +# Potential Use Of Future Funding -Passpod TASK Core is a public open-source standard layer for sensitive-action control: **no receipt, no sensitive action**. +This document describes possible repository-development priorities if future funding, credits, or support become available. -This repository provides schemas, examples, validator/CLI tooling, OpenAPI references, and documentation for Trust Action Receipts and decision states such as `allow`, `deny`, `review_required`, `freeze`, and `revoke`. +It does not claim that funding exists, is being raised, has been awarded, or will be used in a guaranteed way. It does not define a budget, allocation, hiring plan, investor return, revenue forecast, or market-share claim. -## Why API credits matter +## Purpose -Passpod TASK Core is security-sensitive OSS. Developers may copy its schemas, examples, and validation patterns when building AI-agent, automation, approval, or sensitive-action workflows. Weak examples or inconsistent validation could spread unsafe patterns. +Future funding could support maintenance and evaluation of Passpod as a transport-neutral specification repository with a reference Python SDK. -API credits would help maintain and harden the public OSS layer as a solo maintainer. +Funding decisions remain subject to actual funding arrangements and project governance. Authority for funding decisions is not assigned by this document. -## Planned use of API credits +## Possible Priorities -Credits would be used for public repository maintenance only: +Possible future funding priorities may include: -- Codex-assisted schema validation checks -- Validator and CLI test generation -- OpenAPI consistency checks -- Example receipt generation and review -- Regression tests for valid and invalid receipts -- Detection of unsafe or ambiguous examples -- Documentation drift checks -- Release note and changelog drafting -- Issue and pull request triage automation -- Security review of receipt, state, and revocation flows +- specification maintenance; +- conformance tooling; +- fixtures and testing; +- reference SDK quality; +- Profile research; +- security review; +- documentation; +- interoperability experiments; +- pilot evaluation; +- optional transport-binding research. -## Not for private commercial use +These are possible allocations, not promises. -Credits requested for this repository would not be used for private customer operations, private pilot data, commercial backend execution, or production key issuance. +## Excluded Assumptions -Commercial and private systems remain separate from this public OSS standard layer. +This document does not allocate funding to: -## 30 / 60 / 90 day plan +- production hosted infrastructure; +- sales teams; +- guaranteed hiring; +- guaranteed certifications; +- cryptographic systems not designed by the active architecture; +- live Hub development; +- Pilot Access Engine development; +- receipt infrastructure; +- specific fundraising totals; +- investor returns; +- revenue forecasts; +- market-share claims. -### First 30 days +## Governance Boundary -- Harden validator examples -- Add invalid and replay-risk test cases -- Improve README quickstart -- Add clear public/private boundary notes +Funding priorities must not redefine the Standard, Handshake Protocol, Profiles, conformance, schemas, SDK, CLI, or validator behavior. -### First 60 days - -- Expand receipt gallery -- Add OpenAPI/schema drift checks -- Add issue templates for schema, security, docs, and validator feedback - -### First 90 days - -- Add maintainer automation for pull request review -- Publish release workflow notes -- Improve standards crosswalk notes for OWASP, NIST, OpenID, W3C DID/VC, EUDI, MCP, and FIDO +Any future funded work must preserve the distinction between normative architecture, reference implementation, Passpod Pilot, and archive material. diff --git a/PILOT_ACCESS.md b/PILOT_ACCESS.md index 35d7c8a..bce7ed1 100644 --- a/PILOT_ACCESS.md +++ b/PILOT_ACCESS.md @@ -1,16 +1,79 @@ -# Pilot Access +# Passpod Pilot -The public repo helps you understand and validate Passpod TASK Core. +Passpod Pilot is a controlled evaluation path for applying Passpod to real or synthetic workflows. -Upgrade path: +Pilot work may evaluate: -1. Use the public schema, examples, OpenAPI reference, and validator to test the Trust Action Receipt model locally. -2. Request pilot access for a real sensitive-action workflow. -3. If accepted, use scoped Passpod Hub access through the Pilot Access Engine. +- workflow fit; +- handshake modeling; +- Profile candidate discovery; +- implementation feedback; +- evidence expectation discovery; +- conformance questions; +- developer experience feedback. -Pilot Access is the path from public validation to authorized hosted access. -It may support paid pilot, Team, or Enterprise evaluation, but this repo does -not contain production issuer logic, scoped key generation, customer workflows, -commercial strategy, or Passpod Hub internals. +Passpod Pilot does not change the Standard automatically. Pilot learnings require intentional architectural review before they affect normative documents. -Contact: pilots@passpod.io +## Pilot Scope + +A bounded pilot process may include: + +1. Select a workflow. +2. Identify participants. +3. Model the workflow using `PROPOSE -> CHALLENGE -> AGREE -> CLOSE`. +4. Identify evidence expectations and constraints. +5. Run examples through schemas, the validator, SDK, or CLI where appropriate. +6. Document gaps. +7. Determine whether a Profile candidate is justified. +8. Record implementation or conformance feedback. + +This document does not define an application form, intake API, queue, payment flow, access key, approval system, hosted sandbox, or automated onboarding. + +## Pilot Inputs + +Possible pilot inputs may include: + +- synthetic scenarios; +- sanitized workflow descriptions; +- participant-role definitions; +- evidence expectations; +- existing process diagrams; +- interoperability constraints. + +Use synthetic or sanitized data. Do not submit secrets, private keys, tokens, credentials, private pilot records, customer data, or sensitive personal data. + +## Pilot Outputs + +Possible pilot outputs may include: + +- handshake model; +- fixture candidates; +- Profile questions; +- implementation feedback; +- conformance gaps; +- developer-experience observations; +- non-normative recommendations. + +Pilot work does not promise production integration, certification, approval, commercial contract, guaranteed Profile acceptance, live deployment, or cryptographic proof. + +## Contact + +The current evidence-backed pilot contact is: + +```text +pilots@passpod.io +``` + +Participation and scope are evaluated case by case. This document does not define pricing, service tiers, SLA, automatic acceptance, response time, or approval authority. + +## Pilot Boundaries + +Passpod Pilot is not: + +- a production API; +- a key-issuance system; +- a hosted conformance service; +- a certification program; +- an automatic Standard-change mechanism. + +Historical migration note: archived TASK-era materials used names such as Passpod Hub and Pilot Access Engine. Those names are outside the active Passpod v0.1 architecture. From 575b9298a9756a7e99ee11a79ffc67dce21680e6 Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 04:28:41 +0800 Subject: [PATCH 16/18] Audit final Passpod v0.1 release readiness --- ...FINAL_CANONICAL_RELEASE_READINESS_AUDIT.md | 666 ++++++++++++++++++ 1 file changed, 666 insertions(+) create mode 100644 docs/FINAL_CANONICAL_RELEASE_READINESS_AUDIT.md diff --git a/docs/FINAL_CANONICAL_RELEASE_READINESS_AUDIT.md b/docs/FINAL_CANONICAL_RELEASE_READINESS_AUDIT.md new file mode 100644 index 0000000..126a391 --- /dev/null +++ b/docs/FINAL_CANONICAL_RELEASE_READINESS_AUDIT.md @@ -0,0 +1,666 @@ +# Final Canonical Release Readiness Audit + +Audit date: 2026-07-20 + +## 1. Executive Summary + +The canonical Passpod v0.1 architecture is substantially complete and internally consistent across the normative documents, canonical schemas, fixtures, semantic validator, reference Python SDK, CLI, README, quickstart, governance documents, versioning documents, and current CI/gate. + +The repository is not yet ready for a public Git checkpoint tag because non-archive legacy support surfaces remain visible in the tree and still describe TASK-era or receipt-era architecture as current or semi-current guidance. The most important examples are `docs/glossary.md`, `docs/receipt-lifecycle.md`, `docs/security-model.md`, `docs/public-vs-pilot.md`, `docs/production-checklist.md`, `docs/standardization-roadmap.md`, `cli/README.md`, `validator/README.md`, `examples/README.md`, `tools/validate-receipts.py`, and `tools/pilot-readiness.py`. + +These surfaces do not break canonical tests, CI, the SDK, CLI, schemas, or the Passpod v0.1 gate, but they do block repository-wide public documentation readiness and Git checkpoint readiness. + +Recommended next bounded action: migrate or archive remaining legacy support documents and receipt-era utilities. + +## 2. Audit Scope + +Audited surfaces: + +| Area | Assets reviewed | +|---|---| +| Public entry points | `README.md`, `docs/QUICKSTART.md`, `ADOPTION.md`, `PILOT_ACCESS.md`, `COMMERCIAL_BOUNDARY.md`, `FUNDING_USE.md` | +| Normative documents | `docs/STANDARD.md`, `docs/PROTOCOL.md`, `docs/STATE-MODEL.md`, `docs/MESSAGE-MODEL.md`, `docs/PROFILES.md`, `docs/CONFORMANCE.md`, `docs/TERMINOLOGY.md` | +| Governance and release | `GOVERNANCE.md`, `SECURITY.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `CHANGELOG.md`, `VERSIONING.md`, `LICENSE`, `requirements.txt` | +| Implementation | `schemas/`, `examples/valid/`, `examples/invalid/`, `validator/semantic_validator.py`, `passpod/`, `tests/`, `tools/check-public-task-repo.sh`, CI, PR template | +| Historical and migration evidence | `archive/legacy-task/`, audit and migration documents under `docs/` | +| Legacy support surfaces still outside archive | legacy docs under `docs/`, `cli/README.md`, `validator/README.md`, `examples/README.md`, `tools/validate-receipts.py`, `tools/pilot-readiness.py` | + +Baseline commands: + +```text +git status --short +``` + +returned no output. + +```text +git log -20 --oneline +``` + +showed `86815b0 Migrate adoption pilot and commercial boundaries` as the latest commit. + +```text +git tag --list +``` + +returned: + +```text +v0.1.0 +v0.1.1 +``` + +Both tags are historical TASK-era tags. + +## 3. Canonical Architecture Verification + +The canonical architecture is present: + +- Passpod Standard; +- Passpod Handshake Protocol; +- State Model; +- Message Model; +- Profiles; +- Conformance; +- Passpod SDK; +- Passpod Pilot. + +The canonical flow is consistently defined in canonical and current public surfaces: + +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` + +Verified principles: + +| Principle | Result | Notes | +|---|---|---| +| Transport neutrality | PASS | Standard, Protocol, README, Quickstart, Contributing, and implementation boundaries preserve it. | +| Append-only history | PASS | Standard, Protocol, State Model, Conformance, validator, and SDK preserve it. | +| Immutable accepted messages | PASS | State Model and SDK defensive-copy behavior support this. | +| Terminal closure | PASS | State Model, validator, CLI inspection, and tests preserve closed state. | +| Profiles specialize without redefining core semantics | PASS | Profiles document, schema, validator, and invalid fixture enforce this. | +| Standard remains semantic authority | PASS | README, Standard, Conformance, Governance, Quickstart, and Versioning say implementation consumes semantics. | +| SDK/validator/CLI/CI/gate do not become semantic authority | PASS | They validate and implement bounded behavior without replacing the Standard. | + +## 4. Active-versus-Archive Boundary + +The main legacy receipt, OpenAPI, worker-reference, SPEC, roadmap, and launch-readiness families are under `archive/legacy-task/`. + +Archive status: + +- `archive/legacy-task/README.md` clearly says archived material is non-canonical. +- README links archived material only from the legacy terminology/migration context. +- Canonical tests pass when `archive/legacy-task/` is removed in a temporary copy. +- CI, gate, active SDK, active CLI, canonical schemas, canonical fixtures, and tests do not require archived receipt material. + +Remaining issue: + +Some legacy support documents and utilities still live outside `archive/legacy-task/`. They are not canonical dependencies, but they remain discoverable in the repository and carry old TASK/receipt/Pilot Access wording. + +Active dependency on archive content: + +| Surface | Dependency | Classification | +|---|---|---| +| `tools/validate-receipts.py` | archived receipt schema and examples | Legacy utility outside active path | +| `tools/pilot-readiness.py` | archived receipt example shape | Legacy utility outside active path | +| `examples/README.md` | archived receipt examples | Historical guide, but still outside archive | +| `validator/README.md` | archived receipt validator | Historical guide, but still outside archive | + +## 5. Semantic Consistency Findings + +Core canonical terminology is consistent in normative documents and current public entry points: + +- Passpod is transport-neutral trust negotiation. +- The Standard is semantic authority. +- The Protocol is `PROPOSE -> CHALLENGE -> AGREE -> CLOSE`. +- A handshake is bounded negotiation history. +- A message is immutable once accepted into handshake history. +- Participants take part in handshakes. +- Profiles specialize without redefining core semantics. +- Evidence supports, questions, qualifies, or resolves negotiation. +- Extensions must remain compatible. +- Conformance is semantic before technical. +- Passpod Pilot is controlled evaluation, not a production access engine. + +Findings: + +| Finding | Severity | Details | +|---|---|---| +| Canonical docs are internally consistent | Informational | No conflicting core definitions found in the canonical document set. | +| Current public entry points are aligned | Informational | README, Quickstart, Adoption, Pilot, Commercial Boundary, Funding, Governance, Versioning, and Changelog use current Passpod v0.1 terminology. | +| Legacy support docs outside archive conflict with current architecture | Blocker | `docs/glossary.md`, `docs/receipt-lifecycle.md`, `docs/security-model.md`, `docs/public-vs-pilot.md`, `docs/production-checklist.md`, and `docs/standardization-roadmap.md` still describe TASK/receipt-era concepts. | +| Legacy `cli/README.md` contradicts active CLI | Blocker | It says no standalone CLI is shipped, while `python3 -m passpod.cli validate/inspect` is active and tested. | +| Legacy receipt utility docs remain visible | Important | `examples/README.md` and `validator/README.md` are labeled legacy but still contain Hub/Pilot Access wording. | + +## 6. Schema and Fixture Findings + +Canonical root schemas: + +- `schemas/message.schema.json` +- `schemas/handshake.schema.json` +- `schemas/profile.schema.json` + +No legacy receipt schema remains under root `schemas/`. + +JSON parse result: + +```text +parsed 13 canonical JSON files +``` + +Fixture validation result: + +```text +valid fixtures passed: complete-handshake.json, minimal-profile.json, minimal-propose.json, propose-challenge-agree.json, propose-challenge.json +invalid fixtures failed deterministically: close-before-agree.json:CLOSE_BEFORE_AGREE, duplicate-message-id.json:DUPLICATE_MESSAGE_ID, invalid-transition.json:INVALID_TRANSITION, missing-parent.json:PARENT_REQUIRED, redefine-message-type.json:CORE_SEMANTIC_REDEFINITION +``` + +Findings: + +| Finding | Severity | Details | +|---|---|---| +| Canonical schemas parse | Informational | All three root schemas parse as JSON. | +| Canonical fixtures parse | Informational | Five valid and five invalid canonical fixtures parse as JSON. | +| Valid fixtures pass | Informational | All valid fixtures pass the expected validation path. | +| Invalid fixtures fail deterministically | Informational | All invalid fixtures fail with intended semantic error codes. | +| Schemas remain intentionally broad | Deferred by design | Identifier, timestamp, evidence, extension, and version representation remain intentionally unspecified. | + +## 7. Validator Findings + +Public validator operations are present: + +- `validateMessage` +- `validateHandshake` +- `validateProfile` + +Stable error codes include: + +- `SCHEMA_INVALID` +- `DUPLICATE_MESSAGE_ID` +- `HANDSHAKE_ID_MISMATCH` +- `INITIAL_MESSAGE_NOT_PROPOSE` +- `PARENT_REQUIRED` +- `PARENT_NOT_FOUND` +- `PARENT_SELF_REFERENCE` +- `PARENT_NOT_EARLIER` +- `INVALID_TRANSITION` +- `MESSAGE_AFTER_CLOSE` +- `CLOSE_BEFORE_AGREE` +- `CORE_SEMANTIC_REDEFINITION` + +Findings: + +| Finding | Severity | Details | +|---|---|---| +| Validator is bounded and deterministic | Informational | It checks schema shape, parent references, duplicate IDs, transition order, closure, and profile redefinition. | +| Validator does not introduce transport semantics | Informational | No HTTP, storage, cryptography, identity verification, authorization, or business-domain logic found. | +| Validator consumes schemas and normative semantics | Informational | It does not claim to replace the Standard. | +| Legacy receipt validator still exists separately | Important | `tools/validate-receipts.py` is a legacy utility over archive material; it is not CI/SDK/CLI canonical validation. | + +No duplicated or conflicting canonical validation logic was found. + +## 8. SDK Findings + +Package-root imports verified: + +```python +from passpod import Message, Handshake, Profile, PasspodValidationError +``` + +Import check result: + +```text +package-root imports and validator operations OK +``` + +Findings: + +| SDK aspect | Result | Notes | +|---|---|---| +| Defensive copying | PASS | Constructors, properties, and `to_mapping()` use deep copies. | +| Immutable value objects | PASS | Dataclasses are frozen and expose copies. | +| Append returns new handshake | PASS | `Handshake.append()` builds a candidate mapping and returns a new validated instance. | +| Previous history preserved | PASS | Existing history is tuple-backed and not mutated by append. | +| State inspection | PASS | State is limited to `not_started`, `proposed`, `challenged`, `agreed`, `closed`. | +| Validator consumption | PASS | SDK classes call canonical validator operations. | +| No invented semantics | PASS | No transport, storage, signatures, cryptography, identity generation, or business logic found. | + +Package publication readiness remains a separate FAIL because there is no packaging metadata or package release policy. + +## 9. CLI Findings + +Exposed commands: + +- `validate` +- `inspect` + +CLI smoke checks: + +```text +validate valid exit=0 +VALID handshake + +validate invalid exit=1 +INVALID handshake +PARENT_REQUIRED messages[1].parentReference: Every non-initial message must have an applicable parent reference. + +inspect exit=0 +artifact_type: handshake +handshake_identity: hs-complete-001 +state: closed +closed: true +message_count: 4 +messages: +- msg-propose-001 PROPOSE +- msg-challenge-001 CHALLENGE +- msg-agree-001 AGREE +- msg-close-001 CLOSE + +inspect json exit=0 +{"artifact_type":"handshake","closed":true,"handshake_identity":"hs-complete-001","message_count":4,"messages":[{"message_identity":"msg-propose-001","message_type":"PROPOSE"},{"message_identity":"msg-challenge-001","message_type":"CHALLENGE"},{"message_identity":"msg-agree-001","message_type":"AGREE"},{"message_identity":"msg-close-001","message_type":"CLOSE"}],"state":"closed"} +``` + +Findings: + +| CLI aspect | Result | Notes | +|---|---|---| +| Artifact detection | PASS | Deterministic shape detection for message, handshake, profile. | +| Exit codes | PASS | `0` success, `1` recognized invalid artifact, `2` input/detection failure. | +| JSON output | PASS | Stable compact JSON with sorted keys. | +| Error preservation | PASS | Validator error codes are preserved. | +| Bounded inspection | PASS | Does not dump evidence, extension, sender, or recipient payloads. | +| Network behavior | PASS | No network behavior found. | +| CLI documentation conflict | Blocker | `cli/README.md` still says no standalone CLI is shipped. | + +## 10. Test, CI, and Gate Findings + +Required validation: + +```text +PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests +Ran 55 tests in 1.929s +OK + +bash tools/check-public-task-repo.sh +Passpod v0.1 public repository gate passed +``` + +CI findings: + +| CI/gate aspect | Result | Notes | +|---|---|---| +| JSON parsing | PASS | CI parses canonical schemas and valid/invalid fixtures. | +| Unit tests | PASS | CI runs full unittest discovery. | +| Gate | PASS | Gate checks canonical documents, schemas, fixtures, SDK, CLI, and safety boundaries. | +| Workflow permissions | PASS | `contents: read`. | +| PR template | PASS | Matches current v0.1 architecture and validation commands. | +| Gate success wording | PASS | `Passpod v0.1 public repository gate passed`. | +| Historical filename | PASS | `tools/check-public-task-repo.sh` remains a compatibility path only. | + +Missing or brittle checks: + +- CI does not currently audit all non-archive Markdown docs for legacy semantic drift. +- CI does not currently fail on stale legacy docs outside the archive. + +## 11. Documentation Findings + +Current public docs are mostly aligned: + +- `README.md` +- `docs/QUICKSTART.md` +- `ADOPTION.md` +- `PILOT_ACCESS.md` +- `COMMERCIAL_BOUNDARY.md` +- `FUNDING_USE.md` +- `GOVERNANCE.md` +- `SECURITY.md` +- `CONTRIBUTING.md` +- `CHANGELOG.md` +- `VERSIONING.md` + +Documentation blockers: + +| File | Issue | +|---|---| +| `docs/glossary.md` | Defines TASK Core, Hub, Control Packs, AgentTrust, Pilot Access Engine as active glossary terms. | +| `docs/receipt-lifecycle.md` | Defines `Request -> TASK check -> decision -> Trust Action Receipt -> storage/verification/audit`, conflicting with canonical handshake flow. | +| `docs/security-model.md` | Says TASK is a control-and-receipt layer and production signing is through Pilot Access. | +| `docs/public-vs-pilot.md` | Mentions scoped keys, hosted endpoint, and signed pilot receipts. | +| `docs/production-checklist.md` | Centers signatures, storage, verification, freeze/revoke behavior. | +| `docs/standardization-roadmap.md` | Uses old v0.1/v0.2/v1.0 receipt-core ladder. | +| `cli/README.md` | Contradicts active CLI by saying no standalone CLI is shipped. | + +Important follow-ups: + +- `examples/README.md` and `validator/README.md` are labeled legacy but should be moved into archive or rewritten to avoid discoverable Hub/Pilot Access wording. +- `docs/threat-model.md` is mostly reusable but still receipt-framed. + +## 12. Governance Findings + +Governance is accurate and intentionally cautious. + +Unresolved authority issues are explicitly listed and remain unresolved: + +- Standard stewardship; +- normative approval; +- Profile approval; +- repository tag authority; +- SDK/CLI release authority; +- security reporting authority; +- conduct enforcement; +- Pilot approval; +- archive authority; +- commercial-service authority; +- funding authority. + +Finding: + +| Finding | Severity | Details | +|---|---|---| +| Governance avoids invented authority | Informational | It does not create committees, standards bodies, release managers, certification, or community governance claims. | +| Tag authority unresolved | Important | This contributes to Git checkpoint readiness being blocked until stale docs are corrected and tag authority is intentionally exercised. | + +## 13. Security and Privacy Findings + +Security and privacy discipline is strong for the current non-production scope. + +Confirmed: + +- secrets, private keys, tokens, private pilot records, customer data, and sensitive evidence payloads are prohibited; +- synthetic or sanitized pilot data is required; +- CLI inspection output is bounded; +- no cryptographic proof is claimed; +- no production infrastructure security is claimed; +- unsupported transport, HTTP, persistence, identity, authorization, signatures, and cryptography layers are disclosed; +- `pilots@passpod.io` is qualified as evidence-backed but unresolved as a long-term security contact. + +Finding: + +| Finding | Severity | Details | +|---|---|---| +| Security contact is qualified | Informational | `SECURITY.md` avoids claiming a dedicated security address. | +| `tools/pilot-readiness.py` uses production-readiness scoring language | Important | It is legacy and outside CI, but should be migrated or archived before a public checkpoint. | + +## 14. Claims Audit + +Claim search results were classified as follows: + +| Claim type | Result | +|---|---| +| Production readiness/deployment | Disclaimed in active docs; legacy utility still uses production-readiness score wording. | +| Customers/adoption/traction | Disclaimed or bounded in active docs. No unsupported active claims found. | +| Certification/formal recognition | Disclaimed. No unsupported active claim found. | +| Published SDK package | Disclaimed. No package metadata found. | +| Live HTTP API/hosted service | Disclaimed in active docs. Legacy archived OpenAPI exists only in archive. | +| Pricing/SLA/enterprise support | Disclaimed or conditional future possibility. | +| Funding/grants/investors/revenue | Disclaimed or possible future funding only. | +| Cryptographic proof | Disclaimed. | +| Guaranteed interoperability | Disclaimed. | + +Unsupported claims: + +- `tools/pilot-readiness.py` prints `Production Readiness Score` and Pilot Access next-step wording. It is a legacy utility, but it remains outside archive. +- `docs/glossary.md`, `docs/receipt-lifecycle.md`, `docs/security-model.md`, and `docs/public-vs-pilot.md` contain legacy claims outside archive. + +## 15. Version and Tag Findings + +Existing tags: + +| Tag | Classification | +|---|---| +| `v0.1.0` | Historical TASK-era public draft tag | +| `v0.1.1` | Historical TASK-era public validation and launch-readiness checkpoint | + +Version findings: + +- `CHANGELOG.md` correctly separates Unreleased Passpod v0.1 reset work from historical TASK-era tags. +- `VERSIONING.md` correctly separates specification, protocol, schema, Profile, SDK/CLI, repository tag, and archive version domains. +- No schema package release metadata exists. +- No SDK/CLI package version metadata exists. +- Frozen specification wording does not imply a Git tag. + +Readiness: + +- Specification checkpoint readiness: PASS. +- Git tag readiness: FAIL until blocker legacy support surfaces are migrated or archived. +- If the blocker is corrected, a suitable candidate tag is `passpod-spec-v0.1`, because it avoids semantic collision with TASK-era `v0.1.0` and `v0.1.1`. + +## 16. Package Publication Findings + +Python package publication readiness: FAIL. + +Reasons: + +- no `pyproject.toml`; +- no `setup.py` or `setup.cfg`; +- no package version metadata; +- no distribution artifacts; +- no published package installation documentation; +- no release authority decision; +- CI validates local repository usage on Python 3.12 only. + +The SDK and CLI are ready for repository-local use, not package publication. + +## 17. Pilot and Profile Findings + +Pilot evaluation readiness: PASS with scope limits. + +Passpod Pilot is now defined as controlled evaluation for: + +- workflow fit; +- handshake modeling; +- Profile candidate discovery; +- implementation feedback; +- evidence expectation discovery; +- conformance questions; +- developer experience feedback. + +Limits: + +- no application form; +- no pricing; +- no service tiers; +- no SLA; +- no automatic acceptance; +- no approval authority; +- no hosted sandbox; +- no production integration promise. + +Reference Profile readiness: FAIL. + +Reasons: + +- no active Reference Profile exists; +- Profile approval authority is unresolved; +- Profile lifecycle governance is conceptual only; +- no profile-specific fixture family exists. + +## 18. HTTP Binding Findings + +HTTP binding readiness: FAIL. + +Reasons: + +- current protocol is explicitly transport-neutral; +- no active OpenAPI file exists outside the archive; +- no HTTP routes are defined for canonical messages or handshakes; +- Quickstart lists HTTP API as unsupported; +- no storage, signing, identity, authorization, deployment, or production transport design exists. + +This is deferred by design, not a defect in the core specification. + +## 19. Repository Hygiene + +Hygiene checks: + +| Check | Result | +|---|---| +| `.DS_Store` | None found | +| `__pycache__` | None found | +| `.pytest_cache` | None found | +| `.mypy_cache` | None found | +| package metadata artifacts | None found | +| generated distribution/build artifacts | None found | +| Markdown relative links | 81 links across 42 Markdown files resolved | +| workflow YAML parse | Parsed with Ruby YAML | +| temporary copies | Removed successfully | + +Empty obsolete directories found: + +- `.github/ISSUE_TEMPLATE` +- `packages/validator` +- `spec` +- `src` + +These are hygiene issues but not canonical runtime blockers because they contain no tracked files. + +Stale non-archive legacy surfaces are the primary hygiene blocker. + +## 20. Contact Findings + +Email/contact search: + +| Contact | Locations | Classification | +|---|---|---| +| `pilots@passpod.io` | `PILOT_ACCESS.md`, `SECURITY.md`, legacy/migration docs, `tools/pilot-readiness.py` | Evidence-backed pilot contact; qualified security contact; legacy utility still uses it | + +Findings: + +- `PILOT_ACCESS.md` treats `pilots@passpod.io` as the current evidence-backed pilot contact. +- `SECURITY.md` uses the same contact but explicitly says long-term security contact status is unresolved. +- `CODE_OF_CONDUCT.md` does not assign an enforcement contact. +- `tools/pilot-readiness.py` still prints the pilot contact from legacy receipt-scoring output. + +No document silently treats `pilots@passpod.io` as a formally dedicated conduct address. + +## 21. License and Dependency Findings + +License: + +- `LICENSE` is MIT with DIDX copyright. +- `COMMERCIAL_BOUNDARY.md` correctly points to `LICENSE` and does not add rights or restrictions. +- No legal advice is provided by this audit. + +Dependencies: + +- `requirements.txt` contains `jsonschema[format]>=4,<5`. +- CI installs dependencies with `python3 -m pip install -r requirements.txt`. +- SDK and CLI use standard library interfaces plus local package imports. +- Canonical validator uses `jsonschema`. + +Findings: + +| Finding | Severity | Details | +|---|---|---| +| SDK/CLI standard-library claims are accurate | Informational | SDK/CLI do not require third-party runtime dependencies directly. | +| Validator dependency is disclosed | Informational | `requirements.txt` and CI show `jsonschema`. | +| Publication rights/warranty not overstated | Informational | Commercial boundary defers to LICENSE. | + +## 22. Scoring + +| Area | Score | Material deductions | +|---|---:|---| +| Semantic architecture | 91 / 100 | Core architecture is strong; stale non-archive docs leak legacy semantics. | +| Normative-document consistency | 94 / 100 | Canonical docs are consistent; minor unresolved Profile/version governance remains. | +| Machine-readable specification | 88 / 100 | Schemas and fixtures align; representation intentionally broad; no schema version IDs. | +| Validator | 90 / 100 | Deterministic and bounded; legacy receipt validator remains separately visible. | +| SDK | 90 / 100 | Strong local value-object boundary; not packaged or versioned. | +| CLI | 91 / 100 | Good bounded behavior; stale `cli/README.md` contradicts it. | +| Tests and CI | 88 / 100 | Strong canonical coverage; no CI check for stale non-archive legacy docs. | +| Documentation | 72 / 100 | Current public docs are aligned; several legacy support docs remain outside archive. | +| Governance readiness | 70 / 100 | Accurate boundaries; many authorities unresolved. | +| Security/privacy discipline | 82 / 100 | Good disclaimers; shared pilot/security contact unresolved; legacy readiness tool remains. | +| Release readiness | 60 / 100 | Conceptual spec ready; Git checkpoint blocked by stale non-archive legacy surfaces and unresolved tag authority. | +| Production readiness | 15 / 100 | Production use is explicitly unsupported. | + +## 23. Readiness Decisions + +| Decision | Result | Reason | +|---|---|---| +| Conceptual specification freeze | PASS | Canonical docs are consistent and frozen as Passpod Specification v0.1. | +| Canonical repository consistency | FAIL | Remaining non-archive legacy docs/utilities conflict with active architecture. | +| Public documentation readiness | FAIL | `docs/glossary.md`, `docs/receipt-lifecycle.md`, `docs/security-model.md`, `cli/README.md`, and related files remain stale. | +| Git checkpoint/tag readiness | FAIL | Public checkpoint should wait until stale legacy surfaces are migrated or archived. | +| Python package publication readiness | FAIL | No packaging metadata, version metadata, distribution artifacts, or release authority. | +| Pilot evaluation readiness | PASS | Current Pilot docs support bounded evaluation with sanitized/synthetic inputs. | +| Reference Profile readiness | FAIL | No active Reference Profile exists. | +| HTTP binding readiness | FAIL | No active HTTP binding exists; core remains transport-neutral. | +| Production readiness | FAIL | No production transport, persistence, signing, cryptography, identity, authorization, support, or SLA. | + +## 24. Blockers + +| Blocker | Why it blocks public checkpoint/tag readiness | +|---|---| +| Non-archive legacy support docs still describe TASK/receipt-era architecture | They create repository-wide semantic inconsistency and may mislead public readers. | +| `cli/README.md` contradicts active CLI reality | Public docs say no standalone CLI exists while active CLI exists and is tested. | +| Legacy receipt/pilot utilities remain outside archive | `tools/validate-receipts.py` and `tools/pilot-readiness.py` still operate on archived receipt semantics and include production-readiness/Pilot Access language. | + +## 25. Important Follow-ups + +- Move, archive, or rewrite legacy support docs under `docs/`. +- Rewrite or archive `cli/README.md`. +- Rewrite or archive `validator/README.md` and `examples/README.md`. +- Decide treatment for `tools/validate-receipts.py` and `tools/pilot-readiness.py`. +- Add a future gate or documentation audit that fails on active legacy terms outside approved historical/migration contexts. +- Resolve tag/release authority before creating a public checkpoint tag. + +## 26. Deferred-by-Design Capabilities + +- Reference Profiles. +- HTTP binding. +- Production transport. +- Persistence. +- Signatures and cryptography. +- Identity verification. +- Authorization. +- Hosted service. +- Certification or conformance certification. +- Python package publication. +- Commercial services. + +## 27. Recommended Public Checkpoint + +Do not create a public checkpoint tag yet. + +After the blocker is corrected, the recommended candidate tag is: + +```text +passpod-spec-v0.1 +``` + +Rationale: + +- it describes a Passpod specification checkpoint; +- it avoids collision with historical TASK-era tags `v0.1.0` and `v0.1.1`; +- it does not imply a Python package release; +- it does not imply production readiness. + +## 28. Explicit Non-actions + +This audit did not: + +- modify existing files; +- move, archive, rename, or delete files; +- create a release; +- create or change Git tags; +- change versions; +- change implementation; +- change tests; +- change CI or the gate; +- create package metadata; +- browse external claims; +- commit; +- push. + +## 29. Final Recommendation + +Recommended next bounded action: + +```text +Migrate or archive remaining legacy support documents and receipt-era utilities +``` + +Scope should include only the non-archive legacy surfaces identified in this audit, especially `docs/glossary.md`, `docs/receipt-lifecycle.md`, `docs/security-model.md`, `docs/public-vs-pilot.md`, `docs/production-checklist.md`, `docs/standardization-roadmap.md`, `cli/README.md`, `validator/README.md`, `examples/README.md`, `tools/validate-receipts.py`, and `tools/pilot-readiness.py`. + +Do not create a Git tag until that bounded corrective pass is complete and validation still passes. From 4a29a6ddc1b704268ab68206ea22f4f6acd71e69 Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 04:42:29 +0800 Subject: [PATCH 17/18] Migrate remaining support docs and archive legacy tools --- README.md | 4 +- archive/legacy-task/README.md | 35 ++++++-- .../legacy-task/docs/production-checklist.md | 3 + .../legacy-task/docs}/receipt-lifecycle.md | 0 .../docs/standardization-roadmap.md | 3 + .../legacy-task/tools}/pilot-readiness.py | 2 +- .../legacy-task/tools}/validate-receipts.py | 0 cli/README.md | 49 +++++++++--- docs/glossary.md | 47 ++++++----- docs/non-goals.md | 20 ++++- docs/production-checklist.md | 35 +++++++- docs/public-vs-pilot.md | 52 +++++++++++- docs/security-model.md | 46 ++++++++++- docs/standardization-roadmap.md | 33 +++++++- examples/README.md | 80 ++++++++----------- validator/README.md | 61 +++++++------- 16 files changed, 349 insertions(+), 121 deletions(-) create mode 100644 archive/legacy-task/docs/production-checklist.md rename {docs => archive/legacy-task/docs}/receipt-lifecycle.md (100%) create mode 100644 archive/legacy-task/docs/standardization-roadmap.md rename {tools => archive/legacy-task/tools}/pilot-readiness.py (90%) rename {tools => archive/legacy-task/tools}/validate-receipts.py (100%) diff --git a/README.md b/README.md index 98d8756..073aaa5 100644 --- a/README.md +++ b/README.md @@ -177,8 +177,8 @@ Historical migration references: - [Legacy specification](archive/legacy-task/docs/SPEC.md) - [Legacy receipt schema](archive/legacy-task/schemas/trust-action-receipt.schema.json) - [Legacy OpenAPI reference](archive/legacy-task/openapi/passpod-task.public.yaml) -- [Legacy examples guide](examples/README.md) -- [Legacy validator guide](validator/README.md) +- [Legacy receipt examples](archive/legacy-task/examples/) +- [Legacy archive index](archive/legacy-task/README.md) - [Legacy pilot access notes](PILOT_ACCESS.md) - [Legacy commercial boundary notes](COMMERCIAL_BOUNDARY.md) diff --git a/archive/legacy-task/README.md b/archive/legacy-task/README.md index d3f1bb5..185def6 100644 --- a/archive/legacy-task/README.md +++ b/archive/legacy-task/README.md @@ -8,7 +8,10 @@ This material is not canonical Passpod v0.1. Trust Action Receipts are not the p ## Historical Context -The archived schema, examples, specification, roadmap, and launch-readiness documents come from the earlier TASK receipt family. They describe historical Trust Action Receipt concepts, demo receipt examples, receipt-era tooling inputs, and TASK-era launch planning. +The archived schema, examples, specification, roadmap, launch-readiness +documents, support documents, and utilities come from the earlier TASK receipt +family. They describe historical Trust Action Receipt concepts, demo receipt +examples, receipt-era tooling inputs, and TASK-era launch planning. Passpod v0.1 is defined by the Standard, Handshake Protocol, State Model, Message Model, Profile model, Conformance model, canonical schemas, canonical fixtures, semantic validator, SDK core, and CLI. @@ -17,10 +20,15 @@ Passpod v0.1 is defined by the Standard, Handshake Protocol, State Model, Messag - [docs/SPEC.md](docs/SPEC.md) - [docs/LAUNCH_READINESS.md](docs/LAUNCH_READINESS.md) - [docs/ROADMAP.md](docs/ROADMAP.md) +- [docs/production-checklist.md](docs/production-checklist.md) +- [docs/receipt-lifecycle.md](docs/receipt-lifecycle.md) +- [docs/standardization-roadmap.md](docs/standardization-roadmap.md) - [schemas/trust-action-receipt.schema.json](schemas/trust-action-receipt.schema.json) - [examples/remote-worker.receipt.json](examples/remote-worker.receipt.json) - [examples/refund-review.receipt.json](examples/refund-review.receipt.json) - [examples/agent-freeze.receipt.json](examples/agent-freeze.receipt.json) +- [tools/validate-receipts.py](tools/validate-receipts.py) +- [tools/pilot-readiness.py](tools/pilot-readiness.py) - [openapi/passpod-task.public.yaml](openapi/passpod-task.public.yaml) - [openapi/README.md](openapi/README.md) - [worker-reference/README.md](worker-reference/README.md) @@ -57,19 +65,29 @@ The archived OpenAPI document describes the previous receipt-oriented HTTP servi Future HTTP binding work must be designed separately from the core protocol. The archival decision is documented in [../../docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md](../../docs/OPENAPI_TRANSPORT_MATERIAL_DECISION.md). -The archived specification, roadmap, and launch-readiness documents describe the previous TASK-era specification and launch model. They are retained for provenance, decision history, and migration analysis. They are not current normative, roadmap, release, or launch-readiness material for Passpod v0.1. +The archived specification, roadmap, launch-readiness, production-checklist, +receipt-lifecycle, and standardization-roadmap documents describe the previous +TASK-era specification, lifecycle, readiness, and launch model. They are +retained for provenance, decision history, and migration analysis. They are not +current normative, roadmap, release, lifecycle, production-readiness, or +launch-readiness material for Passpod v0.1. + +The archived utilities operate only on archived receipt-era examples and schema +material. They are retained as historical support tools and are not part of the +active validation, SDK, CLI, CI, or repository-gate boundary. ## Legacy Consumers The following legacy consumers may still mention or load archived receipt-era or TASK-era material: -- `tools/validate-receipts.py` -- `tools/pilot-readiness.py` -- `validator/README.md` -- `examples/README.md` +- `archive/legacy-task/tools/validate-receipts.py` +- `archive/legacy-task/tools/pilot-readiness.py` - `archive/legacy-task/docs/SPEC.md` - `archive/legacy-task/docs/LAUNCH_READINESS.md` - `archive/legacy-task/docs/ROADMAP.md` +- `archive/legacy-task/docs/production-checklist.md` +- `archive/legacy-task/docs/receipt-lifecycle.md` +- `archive/legacy-task/docs/standardization-roadmap.md` - `archive/legacy-task/openapi/passpod-task.public.yaml` - `archive/legacy-task/openapi/README.md` - `archive/legacy-task/worker-reference/README.md` @@ -83,3 +101,8 @@ The receipt schema and examples in this directory were moved from the repository The OpenAPI and worker-reference material in this directory was moved from `openapi/` and `worker-reference/` using `git mv` to preserve the history of the legacy transport family. The specification, launch-readiness, and roadmap documents in `archive/legacy-task/docs/` were moved from the repository root using `git mv` to preserve the history of the legacy document family. + +The receipt lifecycle, production checklist, standardization roadmap, receipt +validator utility, and pilot-readiness utility were moved from active support +locations using `git mv` to preserve provenance while removing receipt-era +semantics from the active repository surface. diff --git a/archive/legacy-task/docs/production-checklist.md b/archive/legacy-task/docs/production-checklist.md new file mode 100644 index 0000000..fb56d16 --- /dev/null +++ b/archive/legacy-task/docs/production-checklist.md @@ -0,0 +1,3 @@ +# TASK Production Checklist + +Before production, define requesters, approvers, evidence rules, signatures, storage, verification, retention, escalation, and freeze/revoke behavior. diff --git a/docs/receipt-lifecycle.md b/archive/legacy-task/docs/receipt-lifecycle.md similarity index 100% rename from docs/receipt-lifecycle.md rename to archive/legacy-task/docs/receipt-lifecycle.md diff --git a/archive/legacy-task/docs/standardization-roadmap.md b/archive/legacy-task/docs/standardization-roadmap.md new file mode 100644 index 0000000..fe830b4 --- /dev/null +++ b/archive/legacy-task/docs/standardization-roadmap.md @@ -0,0 +1,3 @@ +# Standardization Roadmap + +v0.1 public draft → public feedback → pilot-tested scenarios → v0.2 schema refinement → external compatibility notes → v1.0 stable receipt core. diff --git a/tools/pilot-readiness.py b/archive/legacy-task/tools/pilot-readiness.py similarity index 90% rename from tools/pilot-readiness.py rename to archive/legacy-task/tools/pilot-readiness.py index a4fbd01..9e81349 100755 --- a/tools/pilot-readiness.py +++ b/archive/legacy-task/tools/pilot-readiness.py @@ -3,7 +3,7 @@ from pathlib import Path if len(sys.argv) != 2: - print("Usage: python3 tools/pilot-readiness.py archive/legacy-task/examples/remote-worker.receipt.json") + print("Usage: python3 archive/legacy-task/tools/pilot-readiness.py archive/legacy-task/examples/remote-worker.receipt.json") raise SystemExit(2) data = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8")) diff --git a/tools/validate-receipts.py b/archive/legacy-task/tools/validate-receipts.py similarity index 100% rename from tools/validate-receipts.py rename to archive/legacy-task/tools/validate-receipts.py diff --git a/cli/README.md b/cli/README.md index 296020d..ab83dab 100644 --- a/cli/README.md +++ b/cli/README.md @@ -1,18 +1,45 @@ -# CLI +# Passpod CLI -No standalone CLI is shipped in this public v0.1 draft. +The current CLI is a thin local interface over the SDK and semantic validator. +It is transport-neutral and does not define production behavior. -For now, use the Python validator from the repository root: +## Commands + +Validate an artifact: ```bash -python3 -m pip install -r requirements.txt -python3 tools/validate-receipts.py +python3 -m passpod.cli validate ``` -Future CLI work should stay limited to public schema validation and local -developer ergonomics unless a separate production design is approved. +Inspect a bounded artifact summary: + +```bash +python3 -m passpod.cli inspect +``` + +Both commands support machine-readable output: + +```bash +python3 -m passpod.cli validate --json +python3 -m passpod.cli inspect --json +``` + +## Exit Codes + +- `0`: command succeeded. +- `1`: the artifact was recognized but invalid. +- `2`: usage, file, parsing, root-shape, or artifact-detection failure. + +## Boundary + +The CLI validates and inspects current Passpod messages, handshakes, and +profiles. It does not define the Standard, Protocol, schemas, validator +semantics, production transport, persistence, signatures, cryptography, +identity verification, authorization, hosted infrastructure, or Profile +implementations. + +## References -The CLI must not implement production signing, issuer internals, scoped key -generation, Passpod Hub internals, customer workflows, or private commercial -logic. Production-valid receipts require authorized issuer access through -Passpod Hub and the Pilot Access Engine. +- [../docs/QUICKSTART.md](../docs/QUICKSTART.md) +- [../passpod/cli.py](../passpod/cli.py) +- [../tests/test_cli.py](../tests/test_cli.py) diff --git a/docs/glossary.md b/docs/glossary.md index 0cc9d64..ca34e25 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -1,21 +1,30 @@ # Glossary -Sensitive Action Control: checking and recording risky actions before execution. - -Trust Action Receipt: portable output of a TASK decision. - -Passpod TASK Core: public standard/test layer for schemas, examples, validation, and reference API shape. - -Passpod Protocol: governance and doctrine for receipt-backed control of sensitive actions. - -Passpod Hub: paid hosted product layer. Hub internals are not included in this public repo. - -Control Packs: focused product workflows powered by Passpod Hub. The canonical public Control Packs are AgentTrust and Remote Worker Trust. - -AgentTrust: Control Pack for agent and automated-action control scenarios. - -Remote Worker Trust: Control Pack for remote-work trust and work-reference scenarios. - -Pilot Access Engine: scoped pilot access path for authorized hosted access. Scoped key generation is not included in this public repo. - -DIDX: company, legal, and registry anchor for the Passpod ecosystem. +This glossary is an informative navigation aid. Normative definitions live in +[TERMINOLOGY.md](TERMINOLOGY.md). + +## Active Terms + +- Passpod: the overall architecture defined by the active specification. +- Passpod Standard: the semantic authority for Passpod. +- Handshake Protocol: the transport-neutral negotiation protocol. +- handshake: one append-only negotiation history. +- message: an immutable accepted protocol statement within a handshake. +- participant: an actor represented in a handshake. +- Profile: a domain-specific specialization of Passpod. +- evidence: information referenced during negotiation. +- reference: a conceptual pointer to another message, evidence item, or resource. +- extension: a compatible specialization point. +- conformance: alignment with the active Passpod semantics. +- Passpod SDK: the reference Python implementation surface in this repository. +- Passpod Pilot: the controlled evaluation path for workflow fit and feedback. +- PROPOSE: the initial proposal message type. +- CHALLENGE: a request for clarification, evidence, or negotiation. +- AGREE: acceptance of negotiated terms. +- CLOSE: terminal closure of a handshake. + +## Legacy Terms + +Archived terminology from the earlier TASK-era architecture is listed in +[TERMINOLOGY.md#archived-legacy-terminology](TERMINOLOGY.md#archived-legacy-terminology). +Those terms are outside the active Passpod v0.1 architecture. diff --git a/docs/non-goals.md b/docs/non-goals.md index b11d4db..2131ab9 100644 --- a/docs/non-goals.md +++ b/docs/non-goals.md @@ -1,3 +1,21 @@ # Non-goals -TASK is not a wallet, surveillance system, social credit score, final decision-maker, or private document database. +Passpod v0.1 defines a transport-neutral semantic architecture and a minimal +reference implementation. It does not define: + +- HTTP transport; +- persistence; +- signatures; +- cryptography; +- identity verification; +- authorization; +- hosted infrastructure; +- certification; +- production deployment; +- Profile implementations; +- pricing or commercial services. + +These boundaries preserve the separation between the Passpod Standard, +Handshake Protocol, schemas, validator, SDK, CLI, Profiles, and Pilot +evaluation. Future work may address some non-goals only through separate design +and governance decisions. diff --git a/docs/production-checklist.md b/docs/production-checklist.md index fb56d16..bc0cbf4 100644 --- a/docs/production-checklist.md +++ b/docs/production-checklist.md @@ -1,3 +1,34 @@ -# TASK Production Checklist +# Production Readiness Boundary -Before production, define requesters, approvers, evidence rules, signatures, storage, verification, retention, escalation, and freeze/revoke behavior. +Passpod v0.1 is not a production deployment checklist. The repository is ready +for specification evaluation, local validation, SDK experimentation, CLI +inspection, and Passpod Pilot evaluation. + +## Current Readiness + +Current repository readiness covers: + +- reading the frozen conceptual specification; +- validating canonical fixtures locally; +- exercising the transport-neutral SDK and CLI; +- evaluating whether workflows fit `PROPOSE -> CHALLENGE -> AGREE -> CLOSE`; +- collecting Pilot feedback and conformance questions. + +## Before Production Work + +Production work requires separate design and governance decisions for: + +- transport; +- persistence; +- security review; +- identity; +- authorization; +- operational processes; +- production infrastructure; +- support and governance responsibilities. + +## References + +- [FINAL_CANONICAL_RELEASE_READINESS_AUDIT.md](FINAL_CANONICAL_RELEASE_READINESS_AUDIT.md) +- [../SECURITY.md](../SECURITY.md) +- [../PILOT_ACCESS.md](../PILOT_ACCESS.md) diff --git a/docs/public-vs-pilot.md b/docs/public-vs-pilot.md index 74d0ffa..36101cd 100644 --- a/docs/public-vs-pilot.md +++ b/docs/public-vs-pilot.md @@ -1,5 +1,51 @@ -# Public vs Pilot +# Public Repository And Pilot -Public repo: schema, examples, local validation. +This document separates the public repository from Passpod Pilot evaluation. -Pilot Access: scoped keys, hosted endpoint, signed pilot receipts, scenario mapping, security review, support. +## Public Repository + +The public repository contains: + +- normative specification documents; +- schemas; +- valid and invalid fixtures; +- semantic validator; +- reference SDK; +- CLI; +- tests; +- governance and supporting documentation; +- historical archive material. + +The public repository is sufficient for reading the active architecture, +running local validation, inspecting fixtures, and experimenting with the +transport-neutral reference implementation. + +## Passpod Pilot + +Passpod Pilot is a controlled evaluation path for: + +- workflow-fit evaluation; +- Profile candidate discovery; +- implementation feedback; +- conformance feedback; +- sanitized or synthetic inputs; +- case-by-case scope. + +Pilot work may inform future design questions, but it does not automatically +redefine the Standard, Protocol, State Model, Message Model, Profiles, or +Conformance. + +## Exclusions + +Passpod Pilot does not define: + +- Pilot Access Engine; +- scoped keys; +- payment workflow; +- hosted API; +- certification; +- production access. + +See [../PILOT_ACCESS.md](../PILOT_ACCESS.md) and +[../COMMERCIAL_BOUNDARY.md](../COMMERCIAL_BOUNDARY.md) for the active pilot and +commercial boundaries. diff --git a/docs/security-model.md b/docs/security-model.md index 9486ba5..2c9c3cc 100644 --- a/docs/security-model.md +++ b/docs/security-model.md @@ -1,3 +1,47 @@ # Security Model -TASK is a control-and-receipt layer. Public examples use demo signatures only. Production signing is handled through Pilot Access. +This document describes implementation-neutral security boundaries for the +active Passpod v0.1 repository. It is informative; the Standard remains the +semantic authority. + +## Semantic Boundaries + +Passpod separates protocol semantics from implementation mechanisms. The +canonical architecture preserves transport neutrality, append-only handshake +history, immutable accepted messages, and terminal closure. + +Profiles may specialize domain expectations, but they do not redefine the +Standard or the canonical message types `PROPOSE`, `CHALLENGE`, `AGREE`, and +`CLOSE`. + +## Validation Boundaries + +Structural validation checks whether an artifact has the expected machine- +readable shape. Semantic validation checks bounded protocol rules such as +message ordering, parent references, closure, and Profile non-redefinition. + +The validator evaluates artifacts against the active specification. It is not +the source of protocol semantics. + +## Implementation Boundaries + +The SDK uses defensive copying at value-object boundaries so caller-owned data +is not shared as mutable internal state. The CLI provides bounded local +validation and inspection; inspection avoids printing full payloads. + +## Not Included + +The active repository does not include: + +- network transport; +- signing; +- cryptography; +- identity verification; +- authorization; +- persistence; +- production infrastructure; +- a security proof; +- production security claims. + +For vulnerability reporting and repository security policy, see +[../SECURITY.md](../SECURITY.md). diff --git a/docs/standardization-roadmap.md b/docs/standardization-roadmap.md index fe830b4..c91a8f2 100644 --- a/docs/standardization-roadmap.md +++ b/docs/standardization-roadmap.md @@ -1,3 +1,34 @@ # Standardization Roadmap -v0.1 public draft → public feedback → pilot-tested scenarios → v0.2 schema refinement → external compatibility notes → v1.0 stable receipt core. +Passpod Specification v0.1 is conceptually frozen. This document is not a +release schedule, standards-body claim, or promise of future recognition. + +## Current Status + +The active repository contains the frozen conceptual specification, canonical +schemas, fixtures, semantic validator, reference SDK, CLI, tests, supporting +documentation, and archived legacy material. + +## Current Priorities + +Current priorities are: + +- canonical repository consistency; +- Profile research; +- conformance evidence; +- interoperability experiments; +- optional transport-binding research. + +These priorities do not create implementation commitments or release dates. + +## Governance Boundary + +Future normative changes require intentional governance approval. Pilot +learning, implementation feedback, or interoperability experiments may inform +future questions, but they do not automatically redefine the Standard, +Protocol, State Model, Message Model, Profiles, or Conformance. + +## Non-claims + +This repository does not claim standards-body recognition, certification, +production readiness, active adoption, or guaranteed interoperability. diff --git a/examples/README.md b/examples/README.md index 7effa30..2b323c4 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,63 +1,53 @@ -# Archived Receipt Examples +# Passpod Examples -The Trust Action Receipt examples described here are archived under -[`../archive/legacy-task/examples/`](../archive/legacy-task/examples/). They are -superseded TASK-era material retained for history, migration analysis, and -provenance. +These examples are canonical Passpod v0.1 fixtures for local validation, SDK +round trips, CLI behavior, and conformance discussion. -These receipts are legacy public examples, not canonical Passpod v0.1 fixtures -and not production-valid receipts. They -use `demo-signature-not-production` and do not include production receipt IDs, -policy references, proof references, customer workflows, issuer internals, or -scoped key logic. +## Valid Fixtures -Production-valid receipts require authorized issuer access through Passpod Hub -and the Pilot Access Engine. +[valid/](valid/) contains artifacts expected to pass schema and semantic +validation: -## [remote-worker.receipt.json](../archive/legacy-task/examples/remote-worker.receipt.json) +- `minimal-propose.json`: a minimal `PROPOSE` message. +- `propose-challenge.json`: a handshake through `CHALLENGE`. +- `propose-challenge-agree.json`: a handshake through `AGREE`. +- `complete-handshake.json`: a closed `PROPOSE -> CHALLENGE -> AGREE -> CLOSE` + handshake. +- `minimal-profile.json`: a minimal Profile model artifact. -Demonstrates a Remote Worker TrustPass-style reference check. +## Invalid Fixtures -- `scenario_id`: `remote_worker_reference_check` -- `action`: `request_work_reference_trustpass` -- `decision`: `review_required` -- Why it matters: work-reference requests should collect consent and context - before a trust decision is made. +[invalid/](invalid/) contains JSON-shaped artifacts expected to fail validation: -## [refund-review.receipt.json](../archive/legacy-task/examples/refund-review.receipt.json) +- `missing-parent.json` +- `invalid-transition.json` +- `close-before-agree.json` +- `duplicate-message-id.json` +- `redefine-message-type.json` -Demonstrates a high-risk refund approval that needs review before execution. +These fixtures are useful for deterministic error-code behavior and negative +conformance checks. -- `scenario_id`: `high_risk_refund_review` -- `action`: `approve_high_risk_refund` -- `decision`: `review_required` -- Why it matters: large or risky refund actions should not execute silently. +## Usage -## [agent-freeze.receipt.json](../archive/legacy-task/examples/agent-freeze.receipt.json) +Validate a fixture from the repository root: -Demonstrates a freeze decision for abnormal agent behavior. - -- `scenario_id`: `agent_emergency_freeze` -- `action`: `freeze_agent_execution` -- `decision`: `freeze` -- Why it matters: unsafe or abnormal agent actions may need immediate pause - before further execution. - -## Validate examples +```bash +python3 -m passpod.cli validate examples/valid/complete-handshake.json +``` -From the repository root: +Inspect a fixture from the repository root: ```bash -python3 -m pip install -r requirements.txt -python3 tools/validate-receipts.py +python3 -m passpod.cli inspect examples/valid/complete-handshake.json ``` -Expected result: +SDK fixture round-trip coverage is exercised in +[../tests/test_sdk_fixture_roundtrip.py](../tests/test_sdk_fixture_roundtrip.py). -```text -schema-valid public demo receipt -``` +## Historical Material -That means the JSON matches the public draft schema and keeps the public demo -safety boundary. It does not mean hosted issuance, production signature -verification, or commercial authorization. +Archived receipt examples are retained at +[../archive/legacy-task/examples/](../archive/legacy-task/examples/) for +history, migration analysis, and provenance. They are not current Passpod v0.1 +fixtures. diff --git a/validator/README.md b/validator/README.md index 4657c4b..7866679 100644 --- a/validator/README.md +++ b/validator/README.md @@ -1,43 +1,46 @@ -# Legacy Receipt Validator +# Passpod Semantic Validator -The legacy receipt validator checks archived Trust Action Receipt examples -against the public JSON Schema and the demo-only safety boundary. +The semantic validator evaluates current Passpod artifacts against the frozen +v0.1 specification. It is an evaluator, not the source of protocol semantics. -It validates that: +## Validation Layers -- each `archive/legacy-task/examples/*.receipt.json` file is JSON; -- each example matches `archive/legacy-task/schemas/trust-action-receipt.schema.json`; -- public examples keep `demo-signature-not-production`; -- public examples do not claim production receipt IDs, policy references, or - proof references. +The validator performs: -## Install +- structural schema validation; +- bounded semantic validation; +- deterministic error-code reporting. -From the repository root: +Semantic checks include message ordering, parent references, duplicate message +identity, terminal closure, and Profile non-redefinition of the core protocol. -```bash -python3 -m pip install -r requirements.txt -``` +## Public Operations -## Run +The public validator operations are: -```bash -python3 tools/validate-receipts.py -``` +- `validateMessage` +- `validateHandshake` +- `validateProfile` -Expected output includes: +They are implemented in [semantic_validator.py](semantic_validator.py). -```text -schema-valid public demo receipt -``` +## Fixtures + +Canonical fixtures live under: + +- [../examples/valid/](../examples/valid/) +- [../examples/invalid/](../examples/invalid/) + +Valid fixtures must pass. Invalid fixtures are intentionally shaped as JSON +artifacts that fail bounded structural or semantic checks. ## Boundary -A passing validator result means the receipt is a valid public demo example. It -does not mean the receipt was issued, signed, stored, or verified by a -production service. +The Standard and Handshake Protocol remain authoritative. The validator +consumes the active semantics and reports evaluation results; it does not +define JSON beyond the canonical schemas, transport behavior, SDK classes, +storage, signatures, cryptography, identity, authorization, or certification. -Production-valid receipts require authorized issuer access through Passpod Hub -and the Pilot Access Engine. This repository does not contain production -signing internals, scoped key generation, issuer logic, customer workflows, or -Passpod Hub internals. +Historical receipt validation tooling is archived at +[../archive/legacy-task/tools/validate-receipts.py](../archive/legacy-task/tools/validate-receipts.py). +It is not current Passpod validation guidance. From 2ead25691348a3a37a5d76441c3c3ecdf0e49aeb Mon Sep 17 00:00:00 2001 From: DIDX Date: Mon, 20 Jul 2026 04:50:52 +0800 Subject: [PATCH 18/18] Confirm Passpod v0.1 specification tag readiness --- ...AL_CANONICAL_RELEASE_READINESS_AUDIT_V2.md | 804 ++++++++++++++++++ 1 file changed, 804 insertions(+) create mode 100644 docs/FINAL_CANONICAL_RELEASE_READINESS_AUDIT_V2.md diff --git a/docs/FINAL_CANONICAL_RELEASE_READINESS_AUDIT_V2.md b/docs/FINAL_CANONICAL_RELEASE_READINESS_AUDIT_V2.md new file mode 100644 index 0000000..5b9f009 --- /dev/null +++ b/docs/FINAL_CANONICAL_RELEASE_READINESS_AUDIT_V2.md @@ -0,0 +1,804 @@ +# Final Canonical Release-Readiness Audit V2 + +## 1. Executive Summary + +This audit repeats the final Passpod v0.1 release-readiness review after the +remaining active support documents were migrated and the receipt-era utilities +were archived. + +Result: the previous checkpoint blockers are resolved. + +The current committed repository is ready for a deliberate public repository +checkpoint tag named: + +```text +passpod-spec-v0.1 +``` + +This readiness is limited to a Passpod Specification v0.1 repository +checkpoint. It does not imply Python package publication, Reference Profile +readiness, HTTP binding readiness, or production readiness. + +Summary decisions: + +| Readiness concept | Decision | +|---|---| +| Conceptual specification freeze | PASS | +| Canonical repository consistency | PASS | +| Public documentation readiness | PASS | +| Git checkpoint/tag readiness | PASS | +| Python package publication readiness | FAIL | +| Pilot evaluation readiness | PASS | +| Reference Profile readiness | FAIL | +| HTTP binding readiness | FAIL | +| Production readiness | FAIL | + +No blockers were found for creating the `passpod-spec-v0.1` repository +checkpoint tag. + +## 2. Changes Since Previous Audit + +The previous audit found that the canonical core was strong but that visible +legacy support documents and receipt-era utilities blocked repository +consistency and checkpoint readiness. + +Recent history now includes: + +```text +4a29a6d Migrate remaining support docs and archive legacy tools +575b929 Audit final Passpod v0.1 release readiness +86815b0 Migrate adoption pilot and commercial boundaries +61a4a4d Migrate changelog and versioning to Passpod v0.1 +68daee8 Migrate governance and contribution docs to Passpod v0.1 +d3e9b54 Archive legacy specification and launch documents +8ab431d Audit root documents and package surfaces +e8b5f41 Archive legacy OpenAPI and worker reference material +22a5fed Decide legacy OpenAPI and transport material treatment +b776a7d Archive legacy receipt schema and examples +c9a497a Migrate CI and PR checks to Passpod v0.1 +1efb41b Migrate public repository gate to Passpod v0.1 +af39a10 Map canonical repository and legacy migration +35699ea Migrate README and quickstart to Passpod v0.1 +3118802 Add minimal Passpod validate and inspect CLI +96d15ee Refine SDK ergonomics and fixture round trips +d42ce39 Freeze Passpod v0.1 specification and add SDK core +``` + +The latest committed cleanup: + +- migrated active support documents to Passpod v0.1 wording; +- archived `docs/receipt-lifecycle.md`; +- archived receipt-era utility scripts; +- replaced active production-checklist and standardization-roadmap paths with + concise current boundary documents; +- left the prior final audit intact as evidence of the earlier blocker state. + +Material score changes: + +| Area | Previous score | V2 score | Reason | +|---|---:|---:|---| +| Validator | 90 | 92 | Legacy receipt validator is no longer active root tooling. | +| CLI | 91 | 94 | CLI README now matches active CLI behavior. | +| Documentation | 72 | 90 | Remaining support docs were migrated or archived. | +| Security/privacy discipline | 82 | 86 | Legacy readiness tool moved to archive; contact authority remains unresolved. | +| Release readiness | 60 | 90 | Previous checkpoint blockers are resolved; package and production readiness remain separate failures. | + +## 3. Audit Scope + +This audit reviewed the current committed repository as of: + +```text +4a29a6d Migrate remaining support docs and archive legacy tools +``` + +Baseline commands: + +```text +git status --short +``` + +No output. The working tree was clean before this report was created. + +```text +git tag --list +v0.1.0 +v0.1.1 +``` + +The audit covered: + +- public and supporting documentation; +- canonical normative documents; +- governance and release surfaces; +- schemas, fixtures, validator, SDK, CLI, tests, tools, CI, and PR template; +- archive material; +- audit and migration evidence. + +The audit did not modify existing files, create tags, change versions, commit, +push, or begin release work. + +## 4. Canonical Architecture Verification + +The repository consistently presents the active architecture as: + +- Passpod Standard; +- Passpod Handshake Protocol; +- State Model; +- Message Model; +- Profiles; +- Conformance; +- reference Python SDK; +- Passpod Pilot. + +The canonical flow remains: + +```text +PROPOSE -> CHALLENGE -> AGREE -> CLOSE +``` + +Verification results: + +| Principle | Result | Evidence | +|---|---|---| +| Transport neutrality | PASS | README, Standard, Protocol, quickstart, SDK/CLI docs, and non-goals preserve transport neutrality. | +| Append-only handshake history | PASS | Standard, Protocol, State Model, validator, SDK tests, and gate preserve append-only history. | +| Immutable accepted messages | PASS | Canonical docs and SDK defensive-copy behavior preserve immutable accepted messages. | +| Terminal closure | PASS | State Model, validator, fixtures, SDK, and CLI preserve closure as terminal. | +| Profiles specialize without redefining core semantics | PASS | Profiles and Conformance docs state this; invalid fixture catches redefinition. | +| Standard remains semantic authority | PASS | Governance, quickstart, validator README, CLI README, and gate all state implementation surfaces consume semantics. | +| Schemas/validator/SDK/CLI/CI/gate do not become independent semantic sources | PASS | Supporting docs describe them as evaluators or implementations, not authorities. | + +No canonical semantic drift was found since the previous audit. + +## 5. Remaining Legacy-Term Audit + +Search terms: + +```text +TASK +TASK Core +TASK Guard +Trust Action Receipt +Sensitive Action Control +Passpod Hub +AgentTrust +Control Packs +Pilot Access Engine +Kill-State +allow +deny +freeze +revoke +receipt +policy_ref +proof_ref +demo_signature +/v1/receipts +``` + +Active non-archive hits were found in 18 files. None teach the receipt-era +architecture as current Passpod behavior. + +| File | Result | Classification | +|---|---|---| +| `README.md` | Legacy terms appear only under "Legacy Terminology" and historical migration references. `allow` appears as ordinary English. | Explicit historical context; archived-material reference; legitimate generic wording. | +| `CHANGELOG.md` | Mentions historical TASK-era tags and archived receipt/TASK material. | Explicit historical context. | +| `VERSIONING.md` | Identifies `v0.1.0` and `v0.1.1` as historical TASK-era snapshots and points TASK-era versions to archive. | Explicit historical context; archived-material reference. | +| `COMMERCIAL_BOUNDARY.md` | Notes archived TASK-era Hub/Pilot Access Engine/receipt-service concepts as outside active architecture. | Explicit historical context. | +| `PILOT_ACCESS.md` | Historical migration note says Passpod Hub and Pilot Access Engine are outside active architecture. | Explicit historical context. | +| `FUNDING_USE.md` | Excludes funding allocation to Pilot Access Engine development and receipt infrastructure. | Explicit exclusion, not active commitment. | +| `docs/QUICKSTART.md` | Lists legacy TASK behavior under unsupported behavior. | Explicit exclusion. | +| `docs/glossary.md` | Points archived TASK-era terminology to `docs/TERMINOLOGY.md`. | Explicit historical context. | +| `docs/public-vs-pilot.md` | Explicitly excludes Pilot Access Engine from Passpod Pilot. | Explicit exclusion. | +| `examples/README.md` | Links archived receipt examples as historical material only. | Archived-material reference. | +| `validator/README.md` | Links archived receipt validation tooling as historical material only. | Archived-material reference. | +| `docs/threat-model.md` | Says "forged receipts" in a one-line generic threat list. | Ambiguous legacy residue, not a blocker. | +| `docs/STANDARD.md` | Uses `allow` as ordinary English. | Legitimate generic wording. | +| `docs/PROTOCOL.md` | Uses `allow` as ordinary English. | Legitimate generic wording. | +| `docs/STATE-MODEL.md` | Uses `allow` as ordinary English. | Legitimate generic wording. | +| `docs/MESSAGE-MODEL.md` | Uses `allow` as ordinary English. | Legitimate generic wording. | +| `docs/PROFILES.md` | Uses `allow` as ordinary English. | Legitimate generic wording. | +| `docs/CONFORMANCE.md` | Uses `MAY` as allowed-option language. | Legitimate normative wording. | + +Special cases: + +| File | Result | Classification | +|---|---|---| +| `docs/TERMINOLOGY.md` | Contains archived legacy terminology section. | Explicit archived terminology. | +| `tools/check-public-task-repo.sh` | Historical filename remains; script contains legacy terms only to check containment. | Compatibility filename and gate check logic. | +| Audit and migration reports | Retain pre-migration paths and terminology as dated evidence. | Explicit historical context. | +| `archive/legacy-task/` | Retains legacy terminology and receipt-era behavior. | Archived material. | + +`docs/threat-model.md` finding: + +- "forged receipts" is not teaching the receipt-era architecture as active + Passpod behavior. +- It is still ambiguous legacy residue because the active architecture now + centers messages, handshakes, evidence references, and artifacts rather than + receipts. +- Severity: Important, not Blocker. + +No unsupported active legacy contamination was found. + +## 6. Active-versus-Archive Boundary + +Archive inventory: + +```text +archive/legacy-task/README.md +archive/legacy-task/docs/LAUNCH_READINESS.md +archive/legacy-task/docs/ROADMAP.md +archive/legacy-task/docs/SPEC.md +archive/legacy-task/docs/production-checklist.md +archive/legacy-task/docs/receipt-lifecycle.md +archive/legacy-task/docs/standardization-roadmap.md +archive/legacy-task/examples/agent-freeze.receipt.json +archive/legacy-task/examples/refund-review.receipt.json +archive/legacy-task/examples/remote-worker.receipt.json +archive/legacy-task/openapi/README.md +archive/legacy-task/openapi/passpod-task.public.yaml +archive/legacy-task/schemas/trust-action-receipt.schema.json +archive/legacy-task/tools/pilot-readiness.py +archive/legacy-task/tools/validate-receipts.py +archive/legacy-task/worker-reference/README.md +``` + +Boundary results: + +| Check | Result | +|---|---| +| Receipt schemas and examples remain archived | PASS | +| OpenAPI and worker-reference remain archived | PASS | +| Legacy specification, roadmap, and launch material remain archived | PASS | +| Receipt lifecycle and receipt-era utilities remain archived | PASS | +| Active `tools/` contains no receipt-era utilities | PASS | +| Archived tools are unused by SDK, CLI, tests, and direct CI validation steps | PASS | +| Archive links are clearly historical and resolve | PASS | +| Archive removal does not break canonical tests | PASS | + +Active references to archive content: + +| File | Reference | Classification | +|---|---|---| +| `README.md` | Legacy specification, schema, OpenAPI, examples, archive index | Historical navigation. | +| `examples/README.md` | Archived receipt examples | Historical section only. | +| `validator/README.md` | Archived receipt validator utility | Historical note only. | +| `GOVERNANCE.md` | `archive/legacy-task/` | Provenance and authority boundary. | +| `VERSIONING.md` | `archive/legacy-task/` | Historical version boundary. | +| `CHANGELOG.md` | `archive/legacy-task/README.md` | Archive context. | + +Important nuance: canonical tests do not require the archive. The CI workflow +does not execute archived assets. The repository gate checks README link +integrity, so archive paths linked from README must continue to resolve while +those historical links remain present. This is a historical-link dependency, +not a canonical semantic dependency. + +No stale active root paths remain for: + +```text +docs/receipt-lifecycle.md +tools/validate-receipts.py +tools/pilot-readiness.py +schemas/trust-action-receipt.schema.json +examples/*.receipt.json +openapi/passpod-task.public.yaml +worker-reference/README.md +SPEC.md +ROADMAP.md +LAUNCH_READINESS.md +``` + +Active replacements for `docs/production-checklist.md` and +`docs/standardization-roadmap.md` are concise current boundary documents. They +are not duplicate copies of the archived originals. + +## 7. Documentation Findings + +| Surface | Result | Notes | +|---|---|---| +| `README.md` | PASS | Presents active architecture and keeps legacy terms isolated. | +| `docs/QUICKSTART.md` | PASS | Commands and SDK example match active implementation. | +| `ADOPTION.md` | PASS | Bounded to evaluation and does not claim actual adoption. | +| `PILOT_ACCESS.md` | PASS | Pilot remains controlled evaluation with synthetic/sanitized inputs. | +| `COMMERCIAL_BOUNDARY.md` | PASS | Avoids pricing, current service, customer, revenue, and deployment claims. | +| `FUNDING_USE.md` | PASS | Describes possible future funding only and excludes obsolete model funding. | +| `docs/glossary.md` | PASS | Informative navigation only; points to normative terminology. | +| `docs/non-goals.md` | PASS | Current v0.1 boundaries are clear. | +| `docs/production-checklist.md` | PASS | Does not imply production readiness. | +| `docs/public-vs-pilot.md` | PASS | Excludes obsolete Pilot Access Engine and hosted API assumptions. | +| `docs/security-model.md` | PASS | Does not claim cryptography or production security. | +| `docs/standardization-roadmap.md` | PASS | Does not promise releases or standards-body recognition. | +| `docs/threat-model.md` | Important | "forged receipts" is ambiguous legacy residue, not a checkpoint blocker. | +| `cli/README.md` | PASS | Matches active `validate` and `inspect` CLI behavior. | +| `validator/README.md` | PASS | Documents active semantic validator and marks receipt tool as archived. | +| `examples/README.md` | PASS | Documents canonical valid/invalid fixtures and labels archived examples historical. | + +Documentation readiness now passes for the specification checkpoint. + +## 8. Schema and Fixture Findings + +Canonical schema inventory: + +```text +schemas/handshake.schema.json +schemas/message.schema.json +schemas/profile.schema.json +``` + +Canonical valid fixtures: + +```text +examples/valid/complete-handshake.json +examples/valid/minimal-profile.json +examples/valid/minimal-propose.json +examples/valid/propose-challenge-agree.json +examples/valid/propose-challenge.json +``` + +Canonical invalid fixtures: + +```text +examples/invalid/close-before-agree.json +examples/invalid/duplicate-message-id.json +examples/invalid/invalid-transition.json +examples/invalid/missing-parent.json +examples/invalid/redefine-message-type.json +``` + +Validation: + +| Check | Result | +|---|---| +| All canonical JSON parses | PASS, 13 files | +| Valid fixtures pass | PASS | +| Invalid fixtures produce deterministic expected codes | PASS | +| Fixture SDK round trips | PASS through test suite | +| Transport-specific fields absent | PASS | +| Storage/signature/cryptography/identity behavior absent | PASS | + +Expected invalid fixture codes: + +| Fixture | Expected code | +|---|---| +| `close-before-agree.json` | `CLOSE_BEFORE_AGREE` | +| `duplicate-message-id.json` | `DUPLICATE_MESSAGE_ID` | +| `invalid-transition.json` | `INVALID_TRANSITION` | +| `missing-parent.json` | `PARENT_REQUIRED` | +| `redefine-message-type.json` | `CORE_SEMANTIC_REDEFINITION` | + +No schema or fixture drift was found since the first audit. + +## 9. Validator Findings + +Public operations: + +```text +validateMessage +validateHandshake +validateProfile +``` + +Validator findings: + +| Check | Result | +|---|---| +| Public operations import | PASS | +| Public operations execute | PASS, all returned valid for canonical valid artifacts | +| Stable error vocabulary | PASS | +| Message ordering checks | PASS | +| Parent-reference checks | PASS | +| Duplicate message identity checks | PASS | +| Terminal closure checks | PASS | +| Profile non-redefinition checks | PASS | +| Validator does not become semantic authority | PASS, docs describe it as evaluator | +| Receipt validator no longer active root tool | PASS | + +Stable validator error vocabulary includes: + +```text +SCHEMA_INVALID +DUPLICATE_MESSAGE_ID +HANDSHAKE_ID_MISMATCH +INITIAL_MESSAGE_NOT_PROPOSE +PARENT_REQUIRED +PARENT_NOT_FOUND +PARENT_SELF_REFERENCE +PARENT_NOT_EARLIER +INVALID_TRANSITION +MESSAGE_AFTER_CLOSE +CLOSE_BEFORE_AGREE +CORE_SEMANTIC_REDEFINITION +``` + +## 10. SDK Findings + +Package-root imports work: + +```text +Message +Handshake +Profile +PasspodValidationError +``` + +SDK findings: + +| Check | Result | +|---|---| +| Package-root exports | PASS | +| Message value object validates | PASS | +| Handshake value object validates | PASS | +| Profile value object validates | PASS | +| Defensive copying | PASS | +| `Handshake.append` returns a new handshake | PASS | +| Existing handshake remains unchanged after append | PASS | +| Supported SDK states only | PASS, fixture handshakes exercise `challenged`, `agreed`, and `closed`; message fixture covers `PROPOSE`. | +| Network behavior absent | PASS | +| Storage behavior absent | PASS | +| Cryptographic behavior absent | PASS | +| Identity-verification behavior absent | PASS | +| Business-domain behavior absent | PASS | + +The SDK remains a minimal reference implementation, not a package release. + +## 11. CLI Findings + +CLI commands: + +```text +python3 -m passpod.cli validate +python3 -m passpod.cli inspect +``` + +Smoke-test results: + +| Command | Exit code | Output summary | +|---|---:|---| +| `python3 -m passpod.cli validate examples/valid/complete-handshake.json` | 0 | `VALID handshake` | +| `python3 -m passpod.cli validate examples/invalid/missing-parent.json` | 1 | `INVALID handshake`; `PARENT_REQUIRED` | +| `python3 -m passpod.cli inspect examples/valid/complete-handshake.json` | 0 | Closed handshake, 4 messages. | +| `python3 -m passpod.cli inspect examples/valid/complete-handshake.json --json` | 0 | JSON summary with closed handshake and 4 messages. | + +CLI findings: + +| Check | Result | +|---|---| +| `validate` command | PASS | +| `inspect` command | PASS | +| JSON output | PASS | +| Exit code 0 | PASS | +| Exit code 1 | PASS | +| Exit code 2 | PASS through test suite | +| Bounded inspection output | PASS | +| No network/storage/crypto/identity behavior | PASS | + +The CLI README now matches the implementation. + +## 12. Test, CI, Gate, and Hygiene Findings + +Validation commands: + +```text +PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests +``` + +Result: + +```text +Ran 55 tests in 1.948s +OK +``` + +```text +bash tools/check-public-task-repo.sh +``` + +Result: + +```text +Passpod v0.1 public repository gate passed +``` + +```text +git diff --check +``` + +Result before report creation: no output. + +```text +git diff --stat +``` + +Result before report creation: no output. + +```text +git status --short +``` + +Result before report creation: no output. + +Additional checks: + +| Check | Result | +|---|---| +| All Markdown relative links resolve | PASS, 101 links | +| Workflow YAML parses | PASS, parsed with Ruby standard YAML parser | +| Workflow permissions minimal | PASS, `contents: read` | +| CI parses canonical JSON | PASS, workflow includes schema and fixture JSON parse step | +| CI runs canonical tests | PASS | +| CI runs Passpod v0.1 gate | PASS | +| Gate success wording canonical | PASS, `Passpod v0.1 public repository gate passed` | +| Historical gate filename compatibility-only | PASS | +| Active `tools/` contains only `tools/check-public-task-repo.sh` | PASS | +| No `.DS_Store`, `__pycache__`, `.pytest_cache`, `.mypy_cache`, or `*.pyc` | PASS | +| Archive removal does not break canonical tests | PASS | +| Removing `docs/STANDARD.md` fails gate | PASS | +| Removing `schemas/message.schema.json` fails gate | PASS | +| Temporary files removed | PASS | + +CI does not execute archived assets. It does, however, require historical +archive links in README to keep resolving because the gate performs link +integrity checks. This is acceptable for the repository checkpoint while the +archive remains part of the repository. + +## 13. Governance Findings + +Governance findings: + +| Finding | Severity | Details | +|---|---|---| +| Governance boundaries preserve the Standard as authority | Informational | SDK, CLI, validator, schemas, tests, CI, and gate are described as consumers of semantics. | +| Formal authority questions remain unresolved | Important | Standard stewardship, normative approval, Profile approval, release authority, security contact, conduct enforcement, pilot approval, and archive authority remain unresolved. | +| No invented standards body or certification authority | Informational | Governance explicitly avoids these claims. | +| Tag action still requires deliberate maintainer action | Informational | This audit recommends a tag but does not create release authority. | + +Governance readiness is sufficient for a repository checkpoint, but not for a +broader formal standards process, package release program, certification +program, or production governance model. + +## 14. Security and Privacy Findings + +Security and privacy findings: + +| Check | Result | +|---|---| +| Synthetic or sanitized Pilot input boundary | PASS | +| Secrets/private keys/tokens/private pilot records prohibited | PASS | +| CLI privacy boundary documented and tested | PASS | +| Unsupported transport/security layers disclosed | PASS | +| Security model avoids cryptography claims | PASS | +| Security model avoids production-security claims | PASS | +| Gate scans for dangerous public leakage patterns | PASS | +| `pilots@passpod.io` qualified as evidence-backed and unresolved long-term security contact | PASS | +| Code of Conduct does not assign a false enforcement contact | PASS | + +No production-grade security, cryptographic proof, key management, penetration +testing, certification, or guaranteed isolation is claimed. + +## 15. Claims and Contact Findings + +Claims audit: + +| Claim category | Result | +|---|---| +| Production readiness | Disclaimed. | +| Adoption or customer claims | Disclaimed or bounded to evaluation. | +| Standards recognition | Disclaimed. | +| Certification | Disclaimed. | +| Published package | Disclaimed. | +| Hosted API | Disclaimed. | +| Pricing, SLA, enterprise support | Disclaimed. | +| Funding, grant, investor, revenue | Disclaimed or described only as possible future funding. | +| Cryptographic guarantees | Disclaimed. | +| Guaranteed interoperability | Disclaimed. | + +Contact audit: + +| Contact | Result | +|---|---| +| `pilots@passpod.io` | Used as pilot contact and evidence-backed security-reporting fallback. Not represented as permanent dedicated security contact. | +| Code of Conduct contact | Not assigned; remains a governance question. | + +No unsupported claim blocks the specification checkpoint. + +## 16. License and Dependency Findings + +License and commercial boundary: + +| Check | Result | +|---|---| +| License present | PASS, MIT license. | +| Commercial boundary defers to license | PASS | +| Commercial boundary does not add license restrictions | PASS | +| Commercial services not claimed as current | PASS | + +Dependencies: + +| Surface | Result | +|---|---| +| `requirements.txt` | Contains `jsonschema[format]>=4,<5`. | +| CI dependency install | `python3 -m pip install -r requirements.txt`. | +| Validator dependency | Uses `jsonschema`. | +| SDK/CLI standard-library claims | Accurate for SDK/CLI direct behavior, aside from local package imports and validator use. | +| Package metadata | None found: no `pyproject.toml`, `setup.py`, `setup.cfg`, `PKG-INFO`, or `*.egg-info`. | + +Python package publication readiness remains a separate failure. + +## 17. Version and Tag Findings + +Existing tags: + +```text +v0.1.0 +v0.1.1 +``` + +Both remain documented as historical TASK-era tags. + +Candidate checkpoint tag: + +```text +passpod-spec-v0.1 +``` + +Tag readiness audit: + +| Check | Result | +|---|---| +| Tag-name collision | PASS, no existing `passpod-spec-v0.1` tag. | +| Semantic ambiguity | PASS, name indicates specification checkpoint, not package or production release. | +| Clean committed tree before report | PASS | +| Changelog accuracy | Important: broadly accurate, but latest support-doc/tool archival is not explicitly itemized. | +| Version-document accuracy | PASS | +| No Python package implication | PASS | +| No production-readiness implication | PASS | +| No repository-consistency blocker | PASS | + +The changelog omission is not a checkpoint blocker because repository state, +archive inventory, and this audit record the current boundary. It should be +cleaned up in a later documentation maintenance pass. + +## 18. Scoring + +| Area | Previous score | V2 score | Material deductions | +|---|---:|---:|---| +| Semantic architecture | 91 / 100 | 94 / 100 | Strong core; exact future Profile/version authority remains unresolved. | +| Normative-document consistency | 94 / 100 | 95 / 100 | Canonical docs remain consistent; conceptual edges remain intentionally unspecified. | +| Machine-readable specification | 88 / 100 | 88 / 100 | Schemas and fixtures align; broad representation and version identifiers remain limited. | +| Validator | 90 / 100 | 92 / 100 | Deterministic and bounded; no longer confused by active root receipt validator. | +| SDK | 90 / 100 | 90 / 100 | Good value-object boundary; still not packaged or versioned. | +| CLI | 91 / 100 | 94 / 100 | CLI docs now match implementation; still intentionally minimal. | +| Tests and CI | 88 / 100 | 91 / 100 | Strong canonical coverage; CI still indirectly depends on archive link resolution through README. | +| Documentation | 72 / 100 | 90 / 100 | Support docs migrated; `docs/threat-model.md` retains one ambiguous receipt phrase. | +| Governance readiness | 70 / 100 | 74 / 100 | Boundaries are accurate; authority questions remain unresolved. | +| Security/privacy discipline | 82 / 100 | 86 / 100 | Legacy readiness tool archived; security contact remains unresolved. | +| Release readiness | 60 / 100 | 90 / 100 | Previous blockers resolved; changelog detail and formal authority remain important follow-ups. | +| Production readiness | 15 / 100 | 15 / 100 | Production use remains explicitly unsupported. | + +Scores were not inflated for deferred capabilities. Package publication, +Reference Profiles, HTTP binding, and production readiness remain separate +failures or deferred capabilities. + +## 19. Readiness Decisions + +| Decision | Result | Reason | +|---|---|---| +| Conceptual specification freeze | PASS | Canonical docs remain internally consistent as Passpod Specification v0.1. | +| Canonical repository consistency | PASS | Active support surfaces no longer teach legacy receipt/TASK architecture as current behavior. | +| Public documentation readiness | PASS | Active public docs are aligned and legacy references are historical or exclusions. | +| Git checkpoint/tag readiness | PASS | No blockers remain for `passpod-spec-v0.1`; existing tags are historical and non-conflicting. | +| Python package publication readiness | FAIL | No package metadata, package version, release authority, or distribution artifacts. | +| Pilot evaluation readiness | PASS | Pilot is bounded to controlled workflow-fit evaluation with sanitized/synthetic inputs. | +| Reference Profile readiness | FAIL | No active Reference Profile exists. | +| HTTP binding readiness | FAIL | No active HTTP binding exists; OpenAPI is archived. | +| Production readiness | FAIL | No production transport, persistence, signing, cryptography, identity, authorization, operations, SLA, or support model. | + +## 20. Blockers + +No blockers were found for creating the `passpod-spec-v0.1` repository +checkpoint tag. + +Resolved previous blockers: + +| Previous blocker | V2 result | +|---|---| +| Non-archive legacy support docs still describe TASK/receipt-era architecture | Resolved. | +| `cli/README.md` contradicts active CLI reality | Resolved. | +| Legacy receipt/pilot utilities remain outside archive | Resolved. | + +## 21. Important Follow-ups + +| Follow-up | Severity | Rationale | +|---|---|---| +| Update `docs/threat-model.md` wording away from "forged receipts" | Important | Not a blocker, but it is ambiguous legacy residue. | +| Add changelog entry for support-doc migration and archived receipt-era tools | Important | Improves release notes before or after checkpoint. | +| Resolve formal tag/release authority | Important | Governance still marks final authority unresolved. | +| Resolve dedicated security-reporting and conduct contacts | Important | Current contact is evidence-backed but not final. | +| Consider a future active-legacy-term audit gate | Important | Current gate protects key surfaces, but not every support document. | +| Decide whether README should keep direct archive links long term | Important | Links are clear and resolved, but they create link-integrity dependence on archive paths. | + +None of these follow-ups blocks the specification checkpoint tag. + +## 22. Deferred-by-Design Capabilities + +The following are intentionally outside the v0.1 repository checkpoint: + +- Python package publication; +- Reference Profiles; +- HTTP binding; +- production transport; +- persistence; +- signatures; +- cryptography; +- identity verification; +- authorization; +- hosted infrastructure; +- certification or conformance certification; +- production deployment; +- pricing, SLA, or enterprise support; +- standards-body recognition. + +These are not blockers because the repository does not claim them as part of +the Passpod Specification v0.1 checkpoint. + +## 23. Recommended Tag + +Recommended explicit checkpoint tag: + +```text +passpod-spec-v0.1 +``` + +Recommended tag form: + +```text +annotated Git tag +``` + +Rationale: + +- describes a Passpod specification checkpoint; +- avoids collision with historical TASK-era tags `v0.1.0` and `v0.1.1`; +- avoids implying Python package publication; +- avoids implying production readiness; +- matches the current committed repository state after blocker cleanup. + +Do not use `v0.1.0` or `v0.1.1` for this checkpoint because those tags already +exist and are documented as historical TASK-era snapshots. + +## 24. Explicit Non-actions + +This audit did not: + +- modify existing files; +- move, rename, archive, or delete files; +- create or modify Git tags; +- create a release; +- change versions; +- commit; +- push; +- change canonical semantics; +- change schemas; +- change fixtures; +- change validator behavior; +- change SDK behavior; +- change CLI behavior; +- change tests; +- change CI; +- change the repository gate; +- create package metadata; +- begin corrective work. + +This audit created exactly one new file: + +```text +docs/FINAL_CANONICAL_RELEASE_READINESS_AUDIT_V2.md +``` + +## 25. Final Recommendation + +Recommended next bounded action: + +```text +Create the passpod-spec-v0.1 annotated Git tag +```