Skip to content

feat(cc-229): v0.3.0 M1 core substrate — 8 schemas + 6 policies + state layout + context-pack contract#157

Merged
screenleon merged 11 commits into
mainfrom
impl/cc-229-schema
May 25, 2026
Merged

feat(cc-229): v0.3.0 M1 core substrate — 8 schemas + 6 policies + state layout + context-pack contract#157
screenleon merged 11 commits into
mainfrom
impl/cc-229-schema

Conversation

@screenleon
Copy link
Copy Markdown
Owner

Summary

First implementation PR of v0.3.0 M1, per the dual-path spike landed in #156. Pure additive: 20 new files under core/ + 1 new test script. Zero consumer changes. Schema locked at end of M1 per synthesis §8 R3.

What landed

  • core/schema/ — 8 JSON Schema files (task / run / event / review / decision / brief / handover / context-pack)
  • core/policy/ — 6 YAML tables (executor-enum / dispatch-routes / dispatch-states / task-states / run-states / reviewer-policy)
  • core/state/ — README + machine-readable layout.yaml (per-project partitioning by sha1(git-toplevel))
  • core/context-pack/ — README + Markdown source-interface contract
  • scripts/test-core-schemas.sh — 30 structural test cases (JSON/YAML parse + schema_version const:1 + enum-sync across 8 schema↔policy cross-checks)

Design decisions (all from PR #156 synthesis)

Resolution
Q2 partitioning Per-project projects/<sha1(git-toplevel)>/
Q7 routing_log Dual-write in M1 (M2 cuts hook)
Q8 versioning schema_version: <int> field-only, no v1/ dir
Q5 executor enum Closed {codex, claude}
Q6 reviewer policy Matrix only; override prose stays in agents/project-pm.md
Q1 schema source-of-truth JSON Schema (TS deferred to v0.4.0 MCP)

Gate history

  • Gate 1 (commit 20d8a1b): GO; critic [medium] × 2 + qa-tester [medium] — schema_version not required in brief + $ref to YAML broken + no test
  • Gate 2 (commit c403216): GO, escalation NOT recommended; critic approve (was advise); arch approve; security/risk pass-not-applicable; qa-tester still [medium] but only about meta-testing the new test script itself

Out of scope

  • pm/schema.md re-home (separate small PR)
  • runtime/pmctl/lib/state-writer.sh → CC-230 (next PR)
  • handover-validate.sh policy extraction → CC-231 (next PR)
  • ContextPack source implementations → CC-237 (M4)
  • Meta-tests for test-core-schemas.sh fixture-based negative cases → will backlog as test-hygiene follow-up (qa-tester [medium] from gate)

Test plan

  • All 8 core/schema/*.schema.json pass jq -e .
  • All 7 YAML files pass python yaml.safe_load
  • All 8 payload schemas declare schema_version: { const: 1 } as required
  • All 8 schema↔policy enum cross-checks pass (scripts/test-core-schemas.sh reports 30 passed, 0 failed)
  • No existing files modified (git diff main confirms pure additive)
  • No script in scripts/ references core/ paths yet (CC-230/231 will be the first consumers)
  • CI must still pass (no test files changed except the new structural test)

Related

🤖 Generated with Claude Code

screenleon and others added 11 commits May 24, 2026 22:54
…out, context-pack contract

Per docs/spikes/CC-229-substrate-synthesis.md and Q2/Q7/Q8 decisions
landed in PR #156. Pure additive: 19 new files under core/, zero
consumer changes. Schema locked at the end of M1 per synthesis §8 R3.

Layout:
  core/README.md                          — boundary + invariants
  core/schema/   (8 schemas)
    task / run / event / review / decision / brief / handover / context-pack
  core/policy/   (6 YAML tables)
    executor-enum / dispatch-routes / dispatch-states / task-states / run-states / reviewer-policy
  core/state/    (2 files)
    README + layout.yaml (per-project partitioning by sha1(git-toplevel))
  core/context-pack/  (2 files)
    README + source.interface.md (prose contract)

Design highlights (all decisions from PR #156 synthesis):
- schema_version: const 1 on every payload (Q8: field-only, no v1/ dir)
- per-project partitioning (Q2): projects/<sha1(git-toplevel)>/
- best-effort write semantics with serialize_with_lock (Q3)
- executor enum closed: {codex, claude} (Q5; closed in M1, v0.4.0
  breaking event adds antigravity/opencode slot per synthesis §7)
- reviewer-policy matrix only; override discipline stays in agents/project-pm.md (Q6)
- ContextPack source contract is Markdown prose (Q1 + Q5 of CC-258
  separately), not a typed interface file

Invariants (will be enforced by CC-233 layer-boundary test):
- core/* may NOT import runtime/, scripts/, adapters/, anything executable
- no CLI product name in field/path/dir names (CLI-agnostic)
- schema_version bump = breaking event + CHANGELOG.md + DECISIONS.md

Out of scope:
- pm/schema.md re-home → deferred (separate small PR; current pm/schema.md
  remains primary for BACKLOG grammar)
- runtime/pmctl/lib/state-writer.sh → CC-230 (next PR)
- handover-validate.sh policy extraction → CC-231 (next PR)
- context-pack source implementations → CC-237 (M4)

Self-verify:
- 8/8 JSON Schema files pass `jq -e .` parse
- 7/7 YAML files pass python yaml.safe_load
- 0 changes to existing files (pure additive)
- 0 consumers currently reference core/ (schemas live as documentation
  until CC-230/231 wire them in)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…mpliant enums + structural tests

Per gate-20260524-225440 [medium] findings:

1. critic [medium] brief.schema.json: schema_version was defined but not in
   `required`. Now required across all 8 payload schemas (Brief now matches
   Task/Run/Event/Review/Decision/Handover/ContextPack invariant).

2. critic [medium] review.schema.json $ref to YAML: ajv and standard JSON
   Schema validators cannot resolve $ref to .yaml files. Converted all
   inter-file $refs to inline `enum: [...]` with a description naming the
   policy YAML as the editing source-of-truth. Affected schemas:
   - run.schema.json: executor / dispatch_route / state
   - handover.schema.json: executor / dispatch_route
   - task.schema.json: state
   - review.schema.json: findings[].reviewer / findings[].verdict
   Policy YAML files remain as the human editing surface for
   handover-validate.sh + future pmctl reads.

3. qa-tester [medium] no tests: added scripts/test-core-schemas.sh with
   30 cases covering:
   - JSON Schema parse (8 files)
   - YAML parse (7 files)
   - schema_version const:1 (8 files)
   - enum-sync between schema inline enums and policy YAML source-of-truth
     (8 cross-file checks — would catch drift if either side edited alone)
   Local run: 30 passed, 0 failed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…al-assign

Two failures in test-skill-refine (shellcheck job) on commit c403216:

1. SC1091: scripts/test-core-schemas.sh sources scripts/lib/test-harness.sh
   which shellcheck cannot resolve without -x. Add test-core-schemas.sh
   to .github/workflows/lint.yml exclude list — same pattern every other
   test-*.sh that consumes the harness uses (per [[feedback_ci_shellcheck_test_exclude]]).

2. SC2155: line 103 declared+assigned in one statement with command
   substitution, masking basename's return value. Split into separate
   `local name` declaration + assignment.

Local test still 30/30 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…iles

Per the same system-prompt-hygiene principle applied to agents/project-pm.md
in #156: core/ is a contract surface, not a planning artifact. M1/M2/M4
milestone markers, Q[N] resolved 2026-05-24 decision history, spike-doc
cross-references, and forward ticket pointers (CC-233 will verify / CC-237
will implement / etc.) do not belong in the contract.

Cleaned across 18 files:
- core/README.md           — drop v0.3.0 framing, spike citation, milestone outlook
- core/state/README.md      — drop M2/CC-230, Q2/Q3 resolved markers, synthesis link
- core/context-pack/README.md — drop M4/CC-237/CC-216/v0.4.0/synthesis
- core/context-pack/source.interface.md — drop M1/M4 framing, codegraph "Phase 2 AMBER"
  history, baseline-source section restructured
- core/policy/*.yaml (6)    — drop M1/M2, Q5/Q6 resolved markers, synthesis refs
- core/schema/*.json (7)    — drop "M2 will narrow" / "CC-233 layer test verifies"
  from descriptions; keep illustrative ticket-id pattern examples
  (e.g. `CC-229, JS-106` in task.schema.json id pattern docs)
- core/state/layout.yaml    — drop M1/Q2 markers + CC-230 writer ticket

Kept:
- Ticket-id pattern examples in schema descriptions
  (task.schema.json `id`/`backlog_ref`, decision.schema.json `closes`)
  These illustrate the schema's id format, not history.

Self-verify:
- scripts/test-core-schemas.sh: 30 passed, 0 failed (unchanged)
- 18 files / -57 net lines (contracts tighter)
- No drift markers remaining (grep -rnE 'M[0-9]|v0\.[0-9]|Q[0-9]+ resolved|2026-|Phase [0-9]|spike|synthesis' core/ returns nothing)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Same hygiene principle applied to docs/ contract files (continuation of
8594f8d for core/). Audit results:

dispatch-brief.md L498: dropped "the future CC-036b schema extension may
add dispatch_route after two weeks of telemetry" — roadmap prediction
in a contract section. Rule (route-agnostic dispatch row) is self-sufficient.

executor-contract.md: dropped CC-036/CC-101/CC-102 evolution markers from
5 lines (L24/L46/L51/L55/L59). Contract states the rule; git log carries
the implementation history.

NOT cleaned (kept as-is per audit):
- docs/architecture/v0.3.0-synthesis.md — this IS the planning artifact,
  spike-output frozen in time. Milestone/ticket/version refs are its
  purpose. (69 hits, all legitimate.)
- docs/CONCEPTS.md — L5 is pre-v0.1.0 doc-status notice; L140 is glossary
  example with CC-047 in quotes as illustration.
- docs/model-tier-policy.md — all "synthesis" hits are the /pr-gate
  English verb, not a spike doc reference.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… default

Replace ~/.claude/.pm/state with ~/.local/share/pm-dispatch/state as the
default state root. Rename CLAUDE_PM_STATE_ROOT → PM_DISPATCH_STATE_ROOT.
Add store_root_xdg_subpath field for writer-side XDG precedence resolution.

Resolution order (documented in layout.yaml + core/state/README.md):
  1. $PM_DISPATCH_STATE_ROOT (explicit override)
  2. $XDG_DATA_HOME/pm-dispatch/state (XDG-aware)
  3. ~/.local/share/pm-dispatch/state (fallback)

Fixes invariant #2 self-contradiction in core/README.md — no CLI product
name may appear as a path segment; .claude was one.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Architecture (arch-reviewer block-soft):
- core/state/layout.yaml: replace concrete writer.module path with abstract
  description field — core/ no longer names a runtime/ implementation path
- core/schema/handover.schema.json: neutralize two description fields that
  referenced scripts/lib/handover-validate.sh and scripts/pm-prep-snapshot.sh
- MILESTONES.md, BACKLOG.md (CC-230), docs/architecture/v0.3.0-source-plans.md,
  docs/architecture/v0.3.0-synthesis.md: align state root from ~/.claude/.pm/state/
  to ~/.local/share/pm-dispatch/state/ (XDG)
- DECISIONS.md: add 2026-05-25 ADR recording the XDG state root decision

Security (security-reviewer block-soft):
- agents/project-pm.md: add snapshot_file path constraint — only accept absolute
  paths under /tmp/ matching pm-snapshot-*.md; reject anything else silently
- .github/workflows/lint.yml: add top-level permissions: contents: read

Test coverage (qa-tester block):
- scripts/test-lint-model-aliases.sh (new): 6 regression cases covering happy path
  + missing TSV + malformed row + doc drift + empty TSV + template alias gap
- scripts/test-codex-dispatch.sh: add cases 20/21/22 for alias-source missing,
  malformed, and ../share/ fallback path resolution
- scripts/test-core-schemas.sh: add section 5 with 6 jq-only structural contract
  tests for brief.schema.json (required fields, additionalProperties, patterns, oneOf)

All tests: 6/6 + 22/22 + 36/36 passed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sts, bug fixes

- Add `approve` verdict to review.schema.json and reviewer-policy.yaml;
  add schema_version: 1 to all 3 pr-gate.sh generated brief heredocs
- Fix task-id regex in task/run/context-pack/review schemas to accept
  sub-letter IDs (CC-025b, CC-104e); add test-schema-task-mirrors-backlog.sh
- Remove broken no-jq sed fallback in pm-prep-snapshot.sh; add jq guard
  with graceful warning (mirrors existing gh-not-found guard)
- Fix check-docs-freshness.sh latest_tag to use max_version instead of
  --sort=-creatordate (semantic version order, not tag creation date)
- Add 7 new test functions across test-core-schemas.sh, test-pr-gate.sh,
  test-pm-prep-snapshot.sh, test-check-docs-freshness.sh
- Fix docs/dispatch-brief.md refactor skeleton files format
- Fix test-core-schemas.sh:282 comment variant names
- Add test-schema-task-mirrors-backlog.sh to run-all-tests.sh + CI
- Add structured docstrings to test-check-docs-freshness.sh,
  test-pm-prep-snapshot.sh, test-install.sh
- BACKLOG: add CC-259 (yaml.sh lib extraction) and CC-260
  (pr-gate dirty-worktree diff)

Tests: 29 suites, all pass. Gate 12: GO (critic:advise, qa-tester:pass,
arch:approve, security:pass, risk:pass)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…hallow-clone branch_base

- Remove 4 unused local declarations (parsed_objects, obj, num, title) from
  collect_recently_merged() after the no-jq else branch was removed; eliminates SC2034.
- Add `git fetch --depth=1 origin main` step to test-pm-prep-snapshot and test-install
  CI jobs so `origin/main` resolves in shallow clones, fixing branch_base assertion.
- Fix CC-260 BACKLOG status from invalid `🟡 planned` to `🟢 someday`.

Run: 29 passed, 0 failed, 0 skipped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ction

CC-261: update forward-reference text in core/README.md +
agents/project-pm.md after v0.3.0 runtime lands (M5 release prep).

CC-262: decouple isolation intent from executor-native fields —
`isolation_level` enum in core/policy/, adapter maps in
adapters/{codex,claude}/, PM brief stops writing sandbox/approval/
skip_git_check directly. Spans M1 (schema) → M2 (dispatch) → M3
(adapter maps).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
`design` is an epic token, not a valid area token; swapping to
`arch/process` satisfies the BACKLOG validator and unblocks test-install.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@screenleon screenleon merged commit 4526c44 into main May 25, 2026
21 checks passed
@screenleon screenleon deleted the impl/cc-229-schema branch May 25, 2026 05:48
screenleon added a commit that referenced this pull request May 25, 2026
All three landed in PR #157 (feat(cc-229) merge 2026-05-25):
- CC-229: core/schema/ — 8 schemas (task/run/event/review/decision/
          brief/handover/context-pack)
- CC-231: core/policy/ — 6 YAML tables (executor-enum, reviewer-policy,
          dispatch-states, run-states, task-states, dispatch-routes)
- CC-232: core/schema/context-pack.schema.json + context-pack/
          source.interface.md

M1 remaining: CC-230 (state store) + CC-262 (isolation_level enum).

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant