Merge current main into PR #3121, preserving reviewed contribution

This commit is contained in:
affaan-m
2026-09-27 20:26:25 -04:00
350 changed files with 18401 additions and 217 deletions
+79
View File
@@ -0,0 +1,79 @@
# Skill-only context carriers
Status: P2a/P2b/P2c implemented and focused checks passed, following the read-only foundation in [PR #3037](https://github.com/affaan-m/ECC/pull/3037). This is a source implementation contract, not an installation, activation, or native discovery certificate.
M1 context profiles determine proposed discovery. Carrier layouts map that proposal into a portable file inventory. Sandbox authority, hooks, tool permissions, task routing, and user settings remain separate. See the [profile contract](context-profiles.md) for Lean/Full and selection semantics.
## Three bounded slices
| Slice | Contract | Boundary |
| --- | --- | --- |
| P2a resource declarations | Registry and plan entries preserve sorted explicit `requiredResources` | `sourcePath` is the mandatory entrypoint; empty declarations do not prove resource or workflow closure |
| P2b carrier planning | `planContextCarrier(options)` emits `ecc.context-carrier.v1` | Pure read-only file projection; no output destination, installed-state probe, or native activation |
| P2c acceptance fixtures | An independently checked disposable tree demonstrates structural materialization | Test-only writer owns its temporary parent; observed file equality does not prove native discovery or invocation |
The generated registry/plan v1 shapes gain an additive `requiredResources` field. Existing profile IDs and declaration schemas retain their meanings. Inspection consumers should tolerate additional output fields. A new carrier consumer must reject an older object missing declaration metadata instead of interpreting it as an empty declaration.
`sourcePath` remains required even when absent from the explicit declaration list. An explicit declaration of `SKILL.md` remains visible. The effective required set is their union, while `resources` inventories all included bundled files. Resource-content digests retain their exact byte semantics; registry and plan provenance also bind declaration changes.
## User-facing preview
```sh
node scripts/ecc.js profile carrier lean@1 --target codex --json
node scripts/ecc.js profile carrier lean@1 --target claude --include skill:security-review --json
node scripts/ecc.js profile carrier full@1 --target pi --exclude skill:python-patterns --selection manual --json
```
The packaged command uses `ecc profile carrier` with the same arguments. Defaults match profile preview: Lean, Codex, and Auto selection intent. Auto remains recorded intent only. The JSON inspection envelope reports a warning and unobserved activation; its `carrier` object lists exact proposed files and source bindings. No files are written. Destination and hook flags are rejected.
The [carrier library](../../scripts/lib/context-carriers.js) accepts the same source/profile/target/selection options as compilation. It compiles from canonical sources, verifies the loaded registry matches the compiled plan, and rejects externally supplied replacement plans or unknown options. Its output is checked against the [carrier schema](../../schemas/context-carrier.schema.json).
The schema validates output shape and rejects unknown fields. Semantic relationships such as exact target/layout agreement and resource completeness are enforced by the generator and independent fixture verifier. Schema validation alone cannot certify a supplied artifact.
## Layouts preserve the exact selection
| Target | Skill root within a future isolated carrier | Generated discovery manifest |
| --- | --- | --- |
| Claude | `skills/` | `.claude-plugin/plugin.json` |
| Codex | `skills/` | `.codex-plugin/plugin.json` |
| Pi | `skills/` | `package.json` with the narrow Pi skills declaration |
| OpenCode | `.opencode/skills/` | None; use the native project skills convention |
| Cursor | `.cursor/skills/` | None; use the native project skills convention |
These are implemented layout proposals, not five certified runtime integrations. Other recognized target IDs return `status: unsupported` with an empty file list and retained proposal inventory; unknown target IDs fail. A legacy install-module declaration gap remains visible independently of layout availability.
Every selected skill contributes its complete bundled tree. Canonical IDs remain stable; destination directories use validated native metadata names, which can differ from canonical directory IDs. Full honors explicit exclusions. Routed and excluded skills contribute no carrier files; routed retrieval remains future work rather than an extra undisclosed bootstrap skill. Generated manifests use a narrow field allowlist and never inherit ECC's monolithic hooks, MCP configuration, agents, commands, or broad instruction lists.
Copy operations retain binary byte digests and sizes rather than embedding decoded bodies. Generated manifests bind exact UTF-8 bytes. Required resources must exist in the selected inventory. Duplicate native names, case-colliding paths, unsafe paths, nested case-insensitive skill entrypoints, or source-plan drift fail before a carrier can be returned.
Preserved skill files can contain their own authority-related metadata, including `allowed-tools`. Planning treats those bytes as data and grants no authority. Before native activation, resolve skill-level metadata against retained user consent and trusted policy; omitting hook and MCP manifest fields is insufficient for that gate.
The artifact binds the source registry, profile, compiler, plan, and adapter implementation/schema digests. `carrierDigest` binds the full proposed artifact before adding its own digest. Hashes are content bindings, not signatures or attestations. No runtime execution or executable-mode preservation is certified.
## Acceptance evidence has a narrow meaning
The source-only fixture helper creates its own temporary parent, stages pinned source bytes, and compares an independently expected tree with observed files. It does not accept a user destination. Tests cover resource omission, extra or changed bytes, binary preservation, source drift, symlink substitution, failed-write cleanup, and unrelated sentinel preservation. Generated content must match its independently compiled expectation; a carrier's self-reported digest cannot redefine acceptance.
Structural evidence and native evidence are distinct:
| Claim | Required evidence |
| --- | --- |
| Materialized file set and byte integrity | Fixture comparison against independent expected source and generated content |
| Bundled resource completeness and relocation | All selected resources present; verification still works after source removal |
| Native visible IDs and exclusions | Future fresh-session probe for a named provider version and install path |
| Skill loading and useful workflow execution | Future native invocation and task-outcome checks |
| Activation, reload, rollback, hooks, whole-context cost | Later dedicated lifecycle, consent, and measurement gates |
No structural result may set native discovery, invocation, activation, or token usage to verified. Whole bundled trees also do not prove complete cross-skill or external runtime dependency closure.
## Contributor and provider provenance
The architecture reuses Jeffrey Montoya's [#2788](https://github.com/affaan-m/ECC/pull/2788) ideas of whole-skill copying and one preview/build inventory. Ownership receipts and staging/rollback mechanics remain queued for P3. Its extra catalog bootstrap and copying of all unselected skills are not carried forward because they would change the approved selection or leak exclusions.
LovePlayCode's [#2844](https://github.com/affaan-m/ECC/pull/2844) grouping and deterministic selection ideas inform the shared inventory. Its broad Full directory projection cannot preserve explicit exclusions, so the carrier uses the canonical selected IDs instead. These source contributions remain independently reviewable with attribution; this work does not merge or close their PRs.
Codex and Pi layout fields are grounded in ECC's existing native manifests; provider mirrors are not used as canonical resources. Claude's [documented path rules](https://code.claude.com/docs/en/plugins-reference#path-behavior-rules) require install-path-specific exclusion tests because default discovery can be additive. OpenCode's [skill-name rules](https://opencode.ai/docs/skills/#validate-names) require the native directory name to match metadata. These constraints inform projection fixtures and do not substitute for fresh-session observations.
## Next gate
Earn native discovery and exclusion evidence using isolated homes and exact provider versions. Then implement transactional activation and recovery using the accepted ownership/receipt contract. Task routing, automatic switching, hook consent integration, and release-default changes remain behind their later gates.
+78
View File
@@ -0,0 +1,78 @@
# ECC-029 carrier slice evidence
Date: September 8, 2026. Milestone: M1 canonical context profiles. The P2a/P2b/P2c stack follows [PR #3037](https://github.com/affaan-m/ECC/pull/3037), based on main `5064474d4d762dc9640234a41617cccb79185cec`. Environment: macOS 26.6.2 arm64, Node 24.9.0, ECC 2.2.1. This source-only report records local development evidence. The packed [carrier contract](context-carriers.md) defines the public boundaries.
## Test-first slices and review regressions
| Slice or regression | RED checkpoint | GREEN checkpoint and evidence |
| --- | --- | --- |
| P2a explicit required-resource output | `3b3a7c72`: 3 resource cases passed, 10 failed for missing declarations | `935861ac`: 13 resource cases pass; resource byte digests retain their meaning, while declaration changes affect provenance |
| P2b pure five-layout file planner | `09ec70d9`: 20 cases fail for the intended missing public module | `bdb317eb`: 22 planner cases pass, including subsequent path-alias regressions |
| Read-only carrier CLI journey | `3b3a7c72`: 1 CLI case passed, 6 failed for missing command behavior | `bdb317eb`: 7 cases pass; deterministic JSON, five layouts, exclusions, unsupported targets, argument rejection, unchanged temporary caller state |
| Packed public surface | `a2963136`: both publish-surface cases fail for the missing carrier contract | `bdb317eb`: 2 cases pass with the library, schema and public contract included |
| Portable path collision rejection | `337c560c`: 20 planner cases passed, 2 failed for case/NFC-equivalent directory prefixes | `bdb317eb`: all 22 pass; aliases with different child names fail before returning an artifact |
| P2c disposable acceptance fixture | `09ec70d9`: the intended helper entry point is absent | `fccadba2`: 19 fixture cases pass, including independent expected-plan and manifest checks, source removal, binary bytes, tampering, symlinks and cleanup |
| Fixture aliases fail before writes | `9454a0d5`: 17 cases passed, 2 failed because staging performed 6 writes before rejection | `fccadba2`: both adversarial cases reject with zero writes |
Preserve the RED/GREEN commits. Independent security/code review checked the file planner and CLI, reproduced the portable ancestor collision, and approved the corrected implementation. The acceptance helper received separate review and remains test-only. Source files and skill bodies are data during these checks; scripts are copied but never executed. Narrow manifests omit hooks and MCP settings, while preserved authority-related skill metadata remains a separate pre-activation policy gate.
## Focused checks and coverage
```sh
./node_modules/.bin/c8 --all \
--include='scripts/lib/context*.js' \
--include='scripts/profile.js' \
--include='scripts/ci/validate-context-profiles.js' \
--reporter=text --reporter=json-summary \
--reports-dir=/tmp/ecc-029-carrier-coverage \
--check-coverage --lines=80 --functions=80 --branches=80 --statements=80 \
node --test tests/lib/context-pack-registry.test.js \
tests/lib/context-profiles.test.js tests/lib/context-resources.test.js \
tests/lib/context-carriers.test.js tests/lib/context-carrier-fixture.test.js \
tests/scripts/profile.test.js tests/scripts/profile-carrier.test.js \
tests/ci/context-profiles.test.js
node tests/scripts/npm-publish-surface.test.js
npm run lint
npm test
git diff --check
```
Focused results: 119 logical cases passed, zero failed or skipped. The breakdown is 18 registry, 12 compiler, 13 resource, 22 carrier, 19 fixture, 25 original CLI, 7 carrier CLI and 3 CI cases. Node's outer TAP summary reports 93 because the original CLI and CI files each wrap their own cases.
Runtime coverage: 98.33% statements/lines, 91.16% branches and 100% functions. All thresholds pass. A separate test-helper-inclusive review run reports 100% statements/lines/functions and 90.54% branches for that helper. Runtime coverage excludes test infrastructure.
## Real inventory and package verification
All ten source-tree Lean/Full combinations across Claude, Codex, Pi, OpenCode and Cursor passed disposable structural verification against the actual canonical inventory. Full contains 286 skills and 464 bundled files. Claude, Codex and Pi add one narrow manifest, giving 465 files; OpenCode and Cursor retain 464. Lean contains 3 skills and 3 source files, plus a manifest where applicable.
At implementation head `d52d3430`, the full `npm test` exited 0 and its legacy aggregate reported 4,423 passed and zero failed. That aggregate does not separately count the new node:test cases, which are reported explicitly above. Full ESLint/Markdown lint and whitespace checks passed before this source-only evidence update.
A real `npm pack` ran the normal prepack build. The archive SHA-256 was `dd0577889bfa09071cbd87b430b200f8d0eaf036c6b0fb583dc71ae2f855fd78`. A disposable consumer installed it with `npm install --offline --ignore-scripts --omit=dev --no-audit --no-fund --userconfig=/dev/null`, using a task-local cache explicitly primed online during the preceding PR-readiness check. This proves an offline cached install, not a dependency-free install.
The installed public dispatcher produced all ten Lean/Full carrier objects with deep equality to the checkout, including their complete digests. Each installed artifact then passed structural materialization using the installed package's own canonical skill resources and an independently compiled expected plan. Full's 464 bundled resources were verified in every layout. The isolated subprocess environment was allowlisted and its disposable home remained absent. Packed runtime resolution confirmed js-yaml 4.3.2.
A separate policy simulation denying Windows file symlinks passed all 54 new resource/carrier/fixture cases with zero skips. Directory links use junctions on Windows. This simulation supplies no native Windows filesystem or provider evidence.
Hosted review of the prerequisite PR subsequently identified dry-run argument ordering and directory-enumeration bounds. Fixes and their dependent-stack revalidation follow; the `d52d3430` results remain a pinned earlier checkpoint.
## September 9 review hardening and final verification
The stack inherits the prerequisite PR's global dry-run fix `9b5e3934` and bounded-reader fix `5f9503e6`. Their RED checkpoints are `c373b7fe` (27 CLI passes, 4 failures) and `ea00894d` (7 support-test failures). The reader keeps all file-byte and identity protections and now limits incremental directory enumeration. Public context-profile documentation describes the exact limits. Source-reader extraction received independent security review; its largest function is 20 lines.
Carrier checkpoint `ebd43bef` independently reproduced the global flag failure: 6 CLI cases passed and 1 failed. Merging the prerequisite fixes in `072a3160` makes all 7 carrier CLI cases pass, including a leading global flag and a flag between an option and its value.
The first merged focused run passed 98 outer tests and failed 2 alias regressions because their old `readdirSync` mocks no longer supplied synthetic alias names to the incremental reader. Test-only correction `46924366` models those same source directories through `opendirSync` instead. Both case/NFC spellings and the mandatory zero-staging-write assertions remain unchanged; independent review reran all 19 fixture cases successfully. No runtime change was needed.
Final focused execution uses the coverage command above plus `tests/lib/context-profile-support.test.js`. It passes 132 logical cases, zero failures or skips: 18 registry, 7 support, 12 compiler, 13 resource, 22 carrier, 19 fixture, 31 original CLI, 7 carrier CLI and 3 CI. Outer TAP reports 100 passes. Runtime coverage is 98.37% statements/lines, 91.43% branches and 100% functions, with every threshold passing.
Both prerequisite and carrier full-suite commands exited 0 with legacy aggregates of 4,429 passed and zero failed. The carrier run began at `072a3160`; its test-only mock correction was applied before the runner reached that fixture file, whose final 19/19 result was observed in the complete run. Runtime and packed files remained unchanged throughout. The final focused run independently exercised the corrected tests. Later changes update source-only evidence.
The rebuilt carrier archive at runtime revision `072a3160` has SHA-256 `45ef651dfab1a9da9af7b7b4b4546c84bc6b325a31a95dac47d52def060649e6`. Its offline cached install and all ten installed-provider-layout Lean/Full parity and structural checks passed again. The archive has 2,628 entries; none of these checks launches a provider. A Git diff verifies final runtime, schemas, manifests, package declarations, lockfiles and packed contracts are byte-identical to that revision.
The prerequisite runtime at `e54fd44c` separately passes 71 focused cases, 98.49% statements/lines, 90.46% branches and 100% functions, plus the full 4,429 aggregate. Its rebuilt offline-consumer archive has SHA-256 `e96826df9b336e180408c7765dcd4e09fca2fb7eb7252cbf84f2ff99d036b1a7`. Later prerequisite commit `be393cb0` only reconciles the source-only dependency evidence. Hosted CI is still pending for the latest PR revision.
Lower-priority review suggestions remain explicit follow-ups: failing projection labels, one exported supported-profile list, richer budget-failure inspection and preserving dual CLI/snapshot diagnostics. Process-lifetime compiler caching is deferred until an immutable snapshot and invalidation contract exists. The current schema fixes the budget at 8,000; alternate ceilings are rejected. Private fixtures currently have only synchronous callers, and noncanonical skill-root directories remain rejected under the existing inventory policy.
## Claims deliberately left unobserved
Native discovery, exact native exclusions, invocation, executable-mode needs, workflow outcomes, activation, hook consent, rollback, automatic routing and actual token savings still require their own gates. Schema validation checks shape; it cannot certify supplied artifact semantics. The independently compiled fixture checks exact layout, selection, file set and bytes. It uses a trusted private temporary parent and does not certify an arbitrary-destination transaction writer against hostile concurrent mutation. No native provider, model, container or VM was launched, and no package was published.
@@ -0,0 +1,128 @@
# Context profile AI evaluation
This development-only evaluator measures whether Lean with Auto selection completes real
coding tasks as well as Full. It lives in `docker/context-profiles/` and is not part of
the published npm package. No provider call occurs without an injected test provider or
the explicit `--allow-real-provider` flag. Reports never approve a release on their own.
## What it compares
`docker/context-profiles/ai-corpus.json` fixes 30 small coding tasks and at least 30
selection probes before execution. Each task is a tiny CommonJS workspace with a bug or
missing behavior; about two thirds benefit from a specific ECC skill and the rest need
none, including tasks with misleading workflow vocabulary. Each task carries a hidden
grader that the agent never sees.
Every task runs in all three arms, in separate fresh workspaces with identical files.
Arm order rotates by task and repeat to reduce fixed ordering effects.
| Arm | Codex install | ECC task context |
| --- | --- | --- |
| Full | Real Full install: every skill natively discoverable | None; the host chooses from its own catalog |
| manual Lean | Real Lean install: three-entry core | The task's preregistered skill, loaded by the launcher |
| Auto Lean | Same Lean install | The resolver's shortlist plus one bounded agent proposal |
Both installs are prepared through the isolated native adapter (`applyStore` then
`prepareNativeProfile`), the same path users get. Before every call the evaluator
re-verifies the install's recorded inventory and stops with `environment-drift` if
Codex changed discovery configuration or skill bytes. Full therefore measures today's
native experience, including its real startup context, rather than a simulated catalog.
## Hidden grading
After the agent exits, the evaluator writes the grader into the workspace and runs it
with Node. Exit zero passes. An agent that plants its own grader file fails. On Node 20
and later the grader runs under Node's permission model with read access limited to the
workspace, so it cannot write files, spawn processes or start workers. Network access is
not restricted by that model; run live evaluations inside the Tier 1 sandbox when that
matters. Provider exit status and claimed success alone never pass a task.
`tests/lib/context-profile-eval-corpus.test.js` proves every grader fails on the initial
files and passes on an independent reference solution kept in
`tests/fixtures/context-eval-references.json`, which is never shown to the agent.
## Setup with a ChatGPT subscription
The Codex adapter supports exactly Codex 0.154.0 and 0.155.1. Install a pinned copy
next to, not over, your everyday Codex:
```sh
npm install --prefix ~/.ecc-eval/codex @openai/codex@0.155.1
```
Create a dedicated login home and sign in once. The file credential store keeps the
login in `auth.json`, which the evaluator can lease:
```sh
mkdir -m 700 -p ~/.ecc-eval/auth
CODEX_HOME=~/.ecc-eval/auth ~/.ecc-eval/codex/node_modules/.bin/codex login \
-c 'cli_auth_credentials_store="file"'
chmod 600 ~/.ecc-eval/auth/auth.json
```
For each call, the evaluator copies `auth.json` into the isolated install's
`CODEX_HOME`, runs Codex, writes any refreshed tokens back to the login home, and always
deletes the copy. It refuses a login home that is your own `~/.codex` or `CODEX_HOME`,
or that other users can read. It never reads your everyday Codex home. Calls run
sequentially, so refreshed tokens cannot race. Usage counts against your subscription's
rate limits. `CODEX_API_KEY` remains an alternative when no `--auth-home` is given.
## Running
Register first, then execute against the retained registration:
```sh
CODEX=$(realpath ~/.ecc-eval/codex/node_modules/@openai/codex/bin/codex.js)
node docker/context-profiles/ai-eval.js --plan \
--executable "$CODEX" --model YOUR_PINNED_MODEL > /tmp/ecc-ai-registration.json
node docker/context-profiles/ai-eval.js --allow-real-provider \
--registration /tmp/ecc-ai-registration.json \
--executable "$CODEX" --model YOUR_PINNED_MODEL \
--auth-home ~/.ecc-eval/auth > /tmp/ecc-ai-metrics.json
```
The registration binds corpus bytes, registry resource digests, both profile plans,
evaluator, launcher, resolver and native adapter digests, model and executable
fingerprints, case order, repeats and analysis thresholds. A changed source stops
execution. Repeated sampling requires the same `--repeats N` at registration and
execution. A changed corpus is a new experiment, never a silent replacement for failed
cases.
Defaults are 300 provider calls, a one-hour overall deadline and five minutes per task
call. Hard limits are 2,000 calls, four hours and ten minutes per call. Proposal calls
retain the launcher's tighter timeout. A single pass of the bundled corpus makes about
90 task calls plus up to one proposal call per Auto task and selection probe. Every
scheduled outcome remains in the denominator after a budget, deadline, provider, drift
or grading failure. Workspaces and installs are removed in `finally`.
## Metrics and statistical limits
The JSON report is built from an allowlist: case IDs, arm, repeat, pass/fail, controlled
failure codes, selected skill IDs, digests, call counts, elapsed time, numeric usage,
install skill counts and the authentication mode. Transcripts, prompts, paths, stderr
and credentials are never emitted or persisted. Valid usage requires one
`turn.completed` record with nonnegative integer input, cached-input and output
counters. Missing or malformed usage is unknown, never zero.
Selection accuracy includes a descriptive 95% Wilson interval. Paired pass-rate
differences against Full use a conservative bounded Hoeffding interval with Bonferroni
correction across the two comparisons. Repeats are averaged within distinct task IDs
first, so repeating tasks never creates new independent tasks. The corpus is purposive,
so no production population generalization is justified.
The preregistered minimum is 30 distinct tasks and 30 selection cases, with a
five-percentage-point noninferiority margin. With 30 tasks the Hoeffding interval is
still wide, so a first live run is expected to report `review-required` without
supporting noninferiority. Use its observed variance to size the next corpus.
## Deterministic verification
```sh
node --test tests/lib/context-profile-eval.test.js tests/lib/context-profile-eval-corpus.test.js
node docker/context-profiles/ai-eval.js --plan
```
Injected providers validate the measurement path, isolation, grading, lease handling
and sanitization. A passing synthetic run validates the framework, never model quality.
A valid CLI report exits zero even when cases fail or the sample is insufficient;
consumers must inspect case results and the gate.
+91
View File
@@ -0,0 +1,91 @@
# Lean, Full, and task selection delivery
ECC-029 advances M1: a canonical `lean@1` / `full@1` context contract. This development branch adds managed generations, experimental task selection, an opt-in isolated Codex session, and a preregistered outcome-evaluation pilot. Public release defaults remain governed by the M1 release gate.
## Development sequence and acceptance
| Stage | Deliverable | Acceptance |
| --- | --- | --- |
| Registry and compiler | One source-backed registry, Lean/Full plans, exact exclusions | Deterministic digests, resource closure, invalid-input fixtures |
| Native carriers | Complete skill trees and allowlisted native manifests | Fresh Claude/Codex inventory, exclusion and relocated resource readback |
| Managed state | Explicit private store, immutable generations, receipts, rollback and recovery | Full to Lean to Full, injected interruption, source drift, ownership and concurrency checks |
| Task selection | Manual, suggest and Auto over a stable base | Explicit IDs, bounded agent proposals, exclusions, manual-only rules, source-bound decisions, output budget |
| Interactive session | Receipt-bound bootstrap in an isolated native Codex home | Exact source and executable identity, bounded stdin resolution, refresh after binary or source drift |
| Disposable acceptance | Packed install in tiered clean environments | All ten layout/profile combinations, native Codex discovery, functional store and resolver |
| Release promotion | Certified activation adapters and outcome evidence | Provider invocation, measured whole-context budget, paired task quality, upgrade/uninstall matrix, reviewed PRs |
The first five stages are the local development target. Release promotion requires its own evidence and must retain explicit unsupported or unobserved states.
## User interface
```text
ecc profile preview lean --target codex --json
ecc profile set lean --state-root /absolute/dedicated/profile-store --selection auto --dry-run --json
ecc profile set lean --state-root /absolute/dedicated/profile-store --selection auto --json
ecc profile status --state-root /absolute/dedicated/profile-store --json
ecc profile mode suggest --state-root /absolute/dedicated/profile-store --json
ecc profile rollback --state-root /absolute/dedicated/profile-store --expected-revision 2 --json
ecc profile recover --state-root /absolute/dedicated/profile-store --json
ecc profile resolve lean --task-input task.json|- --json
ecc profile resolve lean --task-input task.json|- --load --json
ecc profile resolve --state-root /absolute/dedicated/profile-store --task-input task.json --load --json
ecc profile run --state-root /absolute/dedicated/profile-store --task-input task.json --dry-run --json
ecc profile prepare-native --state-root /absolute/dedicated/profile-store --native-root /absolute/dedicated/native-store --json
ecc profile native-status --state-root /absolute/dedicated/profile-store --native-root /absolute/dedicated/native-store --json
ecc profile run --state-root /absolute/dedicated/profile-store --native-root /absolute/dedicated/native-store --task-input task.json --dry-run --json
ecc profile start --state-root /absolute/dedicated/profile-store --native-root /absolute/dedicated/native-store
```
`set` materializes a verified generation and records the configured choice. `generationRoot` identifies the provider-shaped payload. A configured generation does not claim a running provider loaded it. Provider-owned skills can remain visible alongside ECC skills.
`resolve --state-root` uses the saved base, mode and exclusions. It rejects overrides and stale source generations. `mode` preserves the configured profile and explicit selections while recording the new mode transactionally.
A task input contains caller-assigned `sessionId`, `taskId`, positive integer `revision`, and `phase`. Optional fields are `query`, `explicitIds`, `proposedIds`, and `noWorkflow`. Increment revision for material task changes. A changed query, including rewording, also invalidates selection reuse. Task prose is consumed locally and omitted from returned receipts.
```json
{
"sessionId": "session-1",
"taskId": "feature-1",
"revision": 1,
"phase": "implement",
"explicitIds": ["skill:python-patterns"]
}
```
Auto uses explicit user IDs first, then a completed pinned decision, an unambiguous ranked match, one cited skill name, or admitted agent-proposed IDs. Ambiguous free text shortlists up to five candidates for a bounded proposal. Manual uses explicit IDs; suggest emits a proposal without bodies. `--load` returns selected UTF-8 instructions and declared required resources, capped at 32,000 bytes across at most eight skills. `--task-input -` accepts one UTF-8 JSON object on standard input, capped at 65,536 bytes. These byte caps are output and transport bounds, not native tokenizer results.
Save the returned `selection.receipt` as a separate JSON document to use `--previous receipt.json`. `--expected-digest` can bind a load to a prior selection digest. Source, trigger content, routing-policy version, profile, mode, exclusions, session, task revision, phase, and a digest of the query invalidate stale reuse. A pending proposal cannot be reused as a completed decision. Receipts are integrity checks for local operation, not an authorization signature.
An agent can call the resolver at task boundaries and read the returned context. This integration is prompt-advisory. Returning a body never grants tools, invokes shell interpolation, starts a native skill, changes hooks or installs dependencies. Native manual-only flags and authority-bearing metadata are checked before selection. Base profiles remain stable during task routing.
`run` is the explicit task-launch boundary. Ambiguous Auto routing makes one provider proposal call over candidate IDs and descriptions. It accepts zero or one known candidate, then rechecks source bindings, saved state, exclusions and admission policy before loading bodies. Invalid or stale proposals stop before task execution. The proposal has a 30-second timeout and 64 KiB output bound. Codex uses an ephemeral, filesystem-read-only agent session with inherited tools and configuration; the prompt's request to avoid tools is advisory, not enforced tool isolation. Claude disables tools and session persistence for this proposal. Task text is sent to the configured provider, so its normal authentication and data-handling policy apply.
The task call sends the query and selected reference content on standard input to `codex exec -` or `claude --print`, with no added task permissions or hook overrides. Current-provider launches inherit the provider process environment. An isolated native launch passes only the pinned home paths, `PATH`, a fixed locale, a private temporary directory, and required Windows system root; caller credentials, proxy settings, runtime injection and unrelated secrets are excluded. Its timeout is 90 seconds after a proposal or 120 seconds without one, uses an uncatchable termination signal, and captures at most 1 MiB. Dry run reports the pending proposal without a provider call. A zero provider exit code records process completion; task success and native skill invocation remain unverified. Routine interactive turns outside this launcher do not gain automatic routing.
## Isolated native Codex generations
`prepare-native` registers the managed carrier in a fresh ECC-owned home, verifies exact discovery through the allowlisted Codex 0.154.0 or 0.155.1 binary, and only then selects that native generation. It writes a bounded `AGENTS.md` bootstrap bound to the installed CLI source, managed roots, carrier, executable and receipt. It copies no credentials or user configuration and never rewrites the user's provider home. `native-status` checks the recorded generation, executable fingerprint, bootstrap source identity and managed-store binding. A launch pins that verified binary instead of resolving a different executable from PATH. Explicit preparation can refresh a changed executable or installed-source binding while preserving the prior generation and receipts.
`profile start` is an explicit terminal-only boundary. It revalidates the store and native generation, then launches the pinned Codex binary with inherited terminal capabilities and the isolated home. The bootstrap tells the active agent to resolve context at material task boundaries through bounded structured stdin. It remains prompt-advisory, grants no tools or permissions, and persists no task prose or selected skill bodies. Authentication must be completed separately inside the isolated home; the start path does not inherit or copy provider credentials.
Switching the managed profile makes the old native generation stale until `prepare-native` succeeds. To undo a switch, first `rollback` the managed store, then use `native-rollback` with both roots. `native-recover` handles a retained interruption journal without deleting provider data. Existing sessions retain their original context. These commands support isolated Codex generations, not migration of an existing global installation or native activation for other providers.
Discovery evidence comes from the generation's empty project. Task launch inherits the caller's task working directory, whose repository instructions and native configuration may add context or affect policy. Native readiness attests the isolated home's recorded inventory and integrity, not the complete context or permissions of every possible task directory.
## Outcome-evaluation pilot
`docker/context-profiles/ai-eval.js` is a development-only evaluator; it lives outside the published package. It preregisters a fixed corpus before any provider call, binding the corpus, profile plans, registry, implementation, Node runtime, dependency versions, model and executable digests. It supports isolated Claude skill installs for five arms, including a pinned legacy skill-library comparator, and isolated Codex Lean/Full installs without that legacy arm. A hidden grader enters each workspace only after the agent exits and runs read-only where Node supports its permission model.
Real execution requires an explicit flag and provider authentication. Codex uses a dedicated subscription login home (`--auth-home`) or `CODEX_API_KEY`; Claude uses its configured token or Keychain login. A Codex subscription login is leased into each isolated call home, refreshed tokens are returned to the login home, and the leased copy is always removed. The evaluator never reads or copies the user's own Codex home. Results contain allowlisted metrics and hidden-check verdicts, not prompts, transcripts, paths or credentials. See `context-profile-ai-evaluation.md` for the setup, measurement contract and statistical limits.
## Community integration
Jeffrey Montoya's [#2788](https://github.com/affaan-m/ECC/pull/2788) informed whole-tree staging, ownership receipts and reversible generations. LovePlayCode's [#2844](https://github.com/affaan-m/ECC/pull/2844) informed deterministic grouping and explicit exclusion. Jeffrey's [#2945](https://github.com/affaan-m/ECC/pull/2945) informed bounded ID/description ranking and deterministic ties. Canonical source digests replace independent routing-cache authority. [#2740](https://github.com/affaan-m/ECC/pull/2740) remains aligned with native context meters and truthful measurement labels.
These are attributed adaptations of concepts; contributor commits have not been silently relabeled as our implementation. Source PR disposition remains separate.
## Remaining release gates
The store recovers actual process exits at five durable boundaries: prepared journal, file publication, generation publication, receipt publication and state publication. An interruption before the initial ownership marker is published, or a corrupted partial kernel write, is preserved for inspection. These cases do not receive an automatic recovery claim.
Small authenticated Claude pilots now provide task and token observations, but they are descriptive and the evaluation gate remains `review-required`. Adequately powered task-quality canaries and whole-context measurements need additional evidence. The opt-in interactive bootstrap has local source, discovery and terminal-start evidence, but authenticated task behavior and native skill invocation remain unobserved. Isolated Codex registration, switching, refresh and rollback have local native evidence; changing a live user installation still requires its own ownership and recovery contract. Fresh-install default changes, existing-user migration, other-provider activation, hook plans, ECC Tools compatibility, hosted rollout and package publication remain outside this local preview.
@@ -0,0 +1,91 @@
# ECC-029 verification ledger
September 13 baseline branch: `feat/ecc-029-profile-delivery`, incorporating upstream main `8321021c` and the previous carrier branch. The September 21 continuation is recorded below. This report describes local development and packed evidence, not a public release.
## Reproduced failures and fixes
| Failure | RED evidence | Fix and GREEN evidence |
| --- | --- | --- |
| Windows profile CI identity fixtures | Synthetic inode `2 ** 60` reproduces missing-exception assertions because adding one does not change the Number | Guaranteed distinct test inode; host and large-inode fixtures pass |
| npm resource mismatch | Source inventory contains nested `.gitignore` omitted by npm | Publication-control files excluded from canonical resources; ten packed plans match source |
| Implicit-invocation policy race | Change `agents/openai.yaml` after compile and before policy read | Policy bytes revalidated against registry digests; preview/load reject drift |
| Windows managed-root parsing | Drive/UNC decomposition loses root separator | Platform-aware root preservation; drive/UNC tests pass |
| Interactive setup fixture race | Delayed startup sends blank answers and EOF before prompt | Prompt-driven PTY and final input closure; 30 tests and 36 existing-install combinations pass |
| Overconfident keyword Auto | Realistic JS review, RAG research and npm release queries select unrelated top scores | Names and generic scores only shortlist; loading requires explicit IDs or a separately admitted agent proposal |
| Native state and executable drift | Reviewed receipt resealing, stale revision, symlink/FIFO and binary replacement cases | Immutable transition binding, bounded regular-file reads, prepublication checks and pinned binary checks |
| Packaged native binary layout | Linux npm wrapper differs from assumed vendor path | Resolve and fingerprint the actual pinned platform binary; regression and real Podman pass |
New feature tests were introduced before their implementations. Independent review covered ownership, source races, exclusion/dependency policy, Windows paths, command validation, inherited authority, native provenance and failure propagation.
## Final focused verification
```sh
node --experimental-test-coverage --test \
--test-coverage-include='scripts/lib/context-profile-*.js' \
--test-coverage-include='scripts/lib/context-selection.js' \
tests/lib/context-profile-*.test.js tests/lib/context-selection.test.js \
tests/scripts/profile-selection.test.js
```
140 tests pass, zero failures. Aggregate coverage for the listed runtime files: 92.73% lines, 81.74% branches, 96.00% functions. This includes the lightly unit-instrumented native discovery subprocess adapter, which also has real-provider conformance below. These percentages are aggregate, not per-file or repository-wide guarantees. Native unit tests account for 25 cases; launcher/proposal/CLI review accounts for 35.
Final `npm test`, `npm run lint` and `git diff --check` all exit zero. The full runner reports 4,726 legacy-format passes and zero failures, and also executes the new native `node:test` files successfully. Its summary parser counts only `Passed:` output, so the separately measured 140-case focused result above is the precise native-runner count, not a claim that the full-suite summary includes every test format.
## Final fresh packed consumer
Command: `node docker/context-profiles/run-podman.js`. Final frozen run exits zero.
Tested npm archive SHA-256:
```text
34346621a1062358f96b1a3ce2f07ac6fe72067cd735771e30d06e1dc202335e
```
Linux arm64, Node 22.23.1, Codex 0.154.0. Normal packed installation completed during image build. The runtime container used the unprivileged node user, networking disabled, all capabilities dropped, no privilege escalation, no host mounts and no copied credentials. Task containers, image and temporary build directory were removed. The exact archive and acceptance log were retained separately; ordinary dependency build caches may remain.
- All ten Lean/Full target combinations match source plans and independent resource expectations. Lean has three skills. Full has 292 skills and 583 source resource files, plus one generated manifest for Claude, Codex and Pi.
- The packed managed CLI verifies Full to Lean to rollback Full, revision checks, idempotency, exclusions, Auto loading, suggest/manual/dry-run boundaries, receipt reuse and no-workflow reset.
- Packed `prepare-native`, `native-status` and `native-recover` pass. Isolated launch dry-run uses the pinned executable even with no provider on PATH.
- Native Codex discovery matches Lean, Lean plus Angular and Full excluding Python patterns. Resource digests survive marketplace carrier source removal. Six provider-owned system skills are reported separately.
- Actual managed/native product APIs switch 291 ECC skills to three and roll back to 291, preserving the Full exclusion and unrelated prior-home bytes. Every native preparation and rollback uses a fresh app-server and verifies discovery before pointer publication.
- Earlier isolated Claude Code 2.1.247 conformance validates and lists exact Lean/Full-with-exclusion inventory with zero hooks, agents, MCP and LSP components. Its projected token counter is not provider usage.
## Evidence boundaries
No authenticated model calls were made. Auto proposal and task transport, admission failures, executable pinning and state drift are tested with injected executable fixtures. Dry-run and native discovery are tested through actual packed provider executables. Model-driven task success, native skill invocation and token savings remain unobserved; there is no certified routing-quality percentage.
Native readiness attests the isolated generation and discovery in its empty project. Task launch inherits the actual working directory and its repository controls, so complete task-context equivalence is unverified. Codex proposal execution is filesystem-read-only but inherits provider tools; tool avoidance in its prompt is advisory. Claude proposal tools are disabled. Task execution inherits provider policy and requires normal authentication.
The store recovers actual process exits at five durable boundaries. Initial creation interrupted before its ownership marker, corrupted partial writes and numeric filesystem identity precision retain explicit limitations. Live installer migration, other-provider activation, interactive Auto bootstrap, whole-context outcome evaluation and default/release changes remain delivery gates. Native status never claims that an existing session changed context.
## September 21 production-acceptance continuation
Branch: `feat/ecc-029-production-acceptance`, with the working integration snapshot updated to upstream main `43b3a01e`. The writer session stopped at its provider usage limit after integrating the interactive and evaluation slices. A replacement session recovered the exact tmux transcript, process state, task log and worktree before continuing. No test process was still running and no conflicting writer remained active.
Additional RED/GREEN cases cover gaps found during review:
- Complete skill names in questions, quoted data or negated requests previously triggered implicit loading. Names now create candidates only; a user explicit ID or admitted agent proposal is required.
- A pending receipt could previously be reused and skip the provider decision. Receipts now bind routing-policy version and `selected`, `none` or `pending` decision state; only completed decisions can be reused.
- A changed or removed pinned Codex executable could leave native preparation unable to refresh. Explicit preparation may create a newly verified generation while preserving the old receipt and pointer until publication. Ordinary status and start remain fail-closed.
- Isolated native task launch previously inherited every caller environment variable. It now passes only pinned home paths, `PATH`, a fixed locale, a private temporary directory and the required Windows system root. Regression coverage proves unrelated cloud credentials, API keys, proxy settings and `NODE_OPTIONS` are absent.
- The Auto authority check previously missed the shipped `tools` frontmatter field. Scalar and array forms now require manual selection. Malformed task JSON now returns a fixed error without echoing task bytes.
- Provider and sandbox timeouts previously used a catchable termination signal. Launch, proposal, native discovery and sandbox supervision now use `SIGKILL`; a real subprocess that ignores `SIGTERM` verifies the sandbox bound.
- The acceptance driver previously trusted only the sandbox exit code. It now binds the executable and its complete implementation tree, rechecks both identities across preview and execution, and validates backend, tier, real execution, assertion commands, final smoke payload, architecture, layout matrix and evidence boundaries.
The opt-in interactive slice adds bounded UTF-8 task JSON on stdin, receipt-bound bootstrap instructions, installed-source and executable identity checks, exact Codex 0.154.0/0.155.1 version admission, safe refresh, and `profile start`. A real macOS arm64 Codex 0.155.1 run verified Lean, an explicit include, Full with an exclusion, relocated resource digests, stdin resolution, bootstrap visibility, sign-in-screen startup and removed-binary refresh. No credential was copied and no authenticated task turn was made.
The source-only AI pilot fixes 13 selection probes and eight paired artifact tasks before execution. Registration binds corpus, registry, plans, implementation, Node runtime, pinned parser and validator dependency versions, model and binary. The provider adapter uses disposable homes, explicit opt-in, `CODEX_API_KEY`, bounded JSONL, deadlines and call counts. Independent artifact assertions and sanitized metrics are implemented. Synthetic tests validate the measurement path; they do not establish model quality. The 13/8 pilot remains below the 30/30 gate and therefore reports `insufficient-sample` even if every case passes.
Current combined verification after recovery:
- Focused registry, carrier, store, native, interactive, resolver, admission, evaluation, sandbox and CLI suites pass, including the review regressions above.
- The final focused `node:test` run passes 182/182. Claude migration and setup compatibility suites pass 16/16 and 30/30. The complete repository runner passes 4,940/4,940; lint, diff checks and the production dependency audit all pass with zero vulnerabilities.
- The integration snapshot is current with upstream main `43b3a01e`. The latest-main Claude setup change removed obsolete install flags; migration dry-run and setup expectations now match the shipped command while retaining separate settings preservation.
- Clean commit `cda9c4bf` produced package SHA-256 `2ebc804ffc4f4c89fcf4b5ea0a9f644613618c1508292ef9199928157aa228d1`; both final driver receipts record that exact revision with `sourceDirty: false`.
- Real Tier 1 run `ecc-profile-tier1-89ead327-f193-4959-aff4-67cf8d381df3` passes on rootless Podman with a validated final smoke payload, a complete 10,758-added/4-changed layer diff, no credentials and exact cleanup.
- Real Tier 2 run `ecc-profile-tier2-fd4654a2-18b2-45f4-ba87-b8d0cd8bc488` passes on a disposable native macOS arm64 Lume clone with the same package digest. It validates all ten layouts, isolated Codex discovery, no credential transfer, stopped-guest cleanup and artifact-server cleanup. Lume v1 reports a bounded path scan with 49 added and nine changed files; it explicitly does not claim a complete disk diff.
- The initial Tier 2 attempt exposed `/tmp` as the standard macOS symlink to `/private/tmp`. The acceptance verifier now canonicalizes its newly created private directory while the production managed-store guard continues to reject symlinked roots. A second guest run proved the corrected path.
- The default sandbox checkout's 5,000-path capture limit truncated a real Tier 1 install diff and failed closed. The reviewed ECC-029 sandbox implementation raises the bounded cap to 50,000, passes its 26-case boundary suite, and produced both final reports. The driver receipt binds its 51-file implementation digest `a84e09ab848b8cd05f33792c13734f7aabe16bfe16d50d8f8292eb5261a93c3a`.
- No real AI outcome call ran because `CODEX_API_KEY` was absent. Host ChatGPT authentication was neither copied nor exposed to the disposable evaluator.
These boundaries keep the shipped behavior distinct from the M1 release gate. Authenticated outcome observations, a complete Tier 2 disk diff, live-install migration, other-provider activation, whole-context token truth and release defaults remain unverified until their explicit prerequisites are available.
+153
View File
@@ -0,0 +1,153 @@
# Context profiles: read-only foundation
Status: accepted first development slice, P0/P1, September 8, 2026. This document describes the source implementation and its contributor contract. It does not announce a released runtime capability or a change to installation defaults.
ECC context profiles separate the skill-discovery proposal from installation, runtime authority, and measurement. The first slice inventories canonical skills, validates versioned declarations, and produces deterministic read-only plans. It does not yet scope the complete host system prompt.
## Keep the controls separate
| Control | Meaning | Compatibility rule |
| --- | --- | --- |
| Existing install `--profile` | Selects install modules using [install profiles](../../manifests/install-profiles.json) | `minimal`, `opencode`, `core`, `developer`, `security`, `research`, and `full` keep their existing meanings |
| Context profile `lean@1` or `full@1` | Proposes which canonical skill metadata is selected for discovery | No automatic mapping from an install profile; `full@1` is a skill projection, not the complete ECC installation |
| Selection `manual`, `suggest`, or `auto` | Records selection intent in a proposed context plan | No task classifier, agent-directed switching, or automatic application exists in this slice |
| Existing hook profile | Controls existing hook policy through [hook flags](../../scripts/lib/hook-flags.js) | `minimal`, `standard`, and `strict` remain separate; preview never changes hook consent |
| Runtime and capabilities | Execution isolation, tool permissions, secrets, and side effects | A context selection grants no authority and chooses no sandbox |
There is no new `use`, `apply`, or `mode` mutation command. The existing install interface is preserved rather than repurposed.
## Inspect the proposal
From a source checkout, use the existing [ECC dispatcher](../../scripts/ecc.js):
```sh
node scripts/ecc.js profile show --json
node scripts/ecc.js profile show lean@1 --json
node scripts/ecc.js profile preview lean@1 --target codex --selection auto --json
node scripts/ecc.js profile preview full@1 --target claude --selection manual --json
node scripts/ecc.js profile preview lean@1 --target codex --include skill:security-review --exclude skill:python-patterns --json
node scripts/ecc.js profile explain skill:security-review --target codex --json
```
The packaged CLI uses the same `ecc profile ...` arguments. `show` reads profile definitions; `preview` compiles a proposal; `explain` looks up one exact canonical skill ID and reports its source, resources, ownership, and target declarations. These commands neither invoke skills nor write installed settings. The CLI reads its own package sources, independently of the caller's working directory.
CLI preview defaults are `lean@1`, target `codex`, and selection intent `auto`. These are preview defaults, not detected user preferences. The library compiler defaults selection intent to `manual`; consumers should pass the intended value explicitly. Both `lean` and `full` are accepted aliases for the versioned profile IDs.
JSON responses use `ecc.profile-inspection.v1`, including `status`, `summary`, `activation`, `next_actions`, and `artifacts`. A successful preview deliberately reports `status: "warning"` with exit code 0 because runtime activation remains `unobserved`. Invalid requests return an error and exit code 1. A plan reports `active: false` and `disposition: "proposed"`; these fields must survive downstream presentation.
## Public sources and APIs
The source manifests have numeric `schemaVersion: 1`. Generated registry and plan objects identify their output shapes as `ecc.context-registry.v1` and `ecc.context-plan.v1` respectively.
| Source | Responsibility |
| --- | --- |
| [Profile schema](../../schemas/context-profile.schema.json) | Versioned profile ID, registry binding, eager and required selection, and metadata budget |
| [Registry declaration schema](../../schemas/context-pack-registry.schema.json) | Canonical inventory source and explicit per-skill dependency/resource overrides |
| [Lean manifest](../../manifests/context-profiles/lean@1.json) and [Full manifest](../../manifests/context-profiles/full@1.json) | Reviewable selection and budget policy |
| [Skill registry declaration](../../manifests/context-packs/skill-registry@1.json) | Binds the inventory to existing install-module ownership and the canonical skills directory |
| [Registry library](../../scripts/lib/context-pack-registry.js) | Inventory, metadata validation, source hashing, dependency validation, and exact explanation |
| [Profile library](../../scripts/lib/context-profiles.js) | Profile loading, deterministic selection, target projection, and metadata estimation |
| [Shared support](../../scripts/lib/context-profile-support.js) | Bounded source reads, portable paths, schema validation, canonical serialization, and compiler digest |
| [Profile CLI](../../scripts/profile.js) | Read-only inspection envelope and argument validation |
Contributor entry points are:
```js
loadContextRegistry({ repoRoot });
explainContextEntry({ repoRoot, id: 'skill:security-review', target: 'codex' });
loadContextProfile('lean@1', { repoRoot });
compileContextProfile({
repoRoot,
profileId: 'lean@1',
target: 'codex',
selectionMode: 'auto',
include: ['skill:security-review'],
exclude: ['skill:python-patterns'],
});
```
The first two functions are exported by the registry library; the profile library exports the last two and re-exports `explainContextEntry`. The registry also exports `projectionFor(entry, target)` for already validated entries and targets. Consumers should use the loading and compilation APIs instead of duplicating source parsing or building another profile authority.
## Inventory and selection semantics
Each canonical `skills/<directory>/SKILL.md` becomes `skill:<directory>`. Its skill directory must have exactly one owner in [install modules](../../manifests/install-modules.json). The owning module supplies `ownerModuleId`, the initial `packId`, and `declaredInstallTargets`. This reuses existing ownership without treating installer module dependencies as skill workflow dependencies.
Lean currently selects three required candidate entries: `skill:configure-ecc`, `skill:context-budget`, and `skill:ecc-guide`. Other canonical skills remain labeled `routed` unless explicitly included or excluded. Here, `routed` means available in the catalog for future discovery integration; it does not mean a router has run or a native host can already retrieve the skill.
Full derives `all` from the current canonical inventory. The September 8 baseline contains 286 skills, but 286 is a snapshot, not a hardcoded profile limit. Explicit exclusions can narrow a Full proposal, except for required entries and dependencies needed by retained selections.
Includes add exact IDs and their transitively declared dependencies. Exclusions cannot remove required profile entries or break that declared closure. Unknown IDs, duplicate selectors, overlapping include/exclude requests, unknown targets, and invalid selection modes fail. Profiles must include their declared required entries in the eager selection.
Dependencies come only from `overrides[].dependencies` in the registry declaration. The current manifest has no overrides, and entries report `dependencyCoverage: "declared-only-unreviewed"`. An empty dependency array means no declaration exists; it does not prove that a workflow is self-contained. References in skill prose are not followed, interpreted, or promoted into dependency edges.
`overrides[].requiredResources` can assert that files exist within that skill's own directory. Unknown override IDs, duplicate ownership, missing resources, unknown dependencies, cycles, malformed metadata, unsafe paths, and symbolic links within the source tree are rejected. Reads are bounded at 4 MiB per file, 16 MiB per source reader, 10,000 files, and 32 levels of recursive directory depth. Directory enumeration is incremental, with at most 10,000 accepted names per directory and 20,000 traversal operations per reader. Every directory open and enumerated entry consumes that shared budget, including empty directories and excluded names; detecting overflow may inspect one extra entry. Generated Python caches, `.git`, and `node_modules` are excluded; an explicitly required excluded resource is rejected.
P2a adds sorted explicit `requiredResources` to registry and plan entries. The mandatory `sourcePath` entrypoint remains distinct; effective required paths are their union. Empty declarations do not establish resource closure, and carriers must not infer that arbitrary subsets are sufficient. The first carrier implementation projects all bundled files for selected skills; see the [P2 carrier contract](context-carriers.md).
Source reads revalidate ancestor and file identities before consuming bytes and after reading. These consistency checks reject the tested concurrent symlink substitution; they do not provide an atomic repository snapshot. Use immutable source artifacts for downstream execution. Skill and profile metadata reject terminal controls; CLI text also renders controls inert in error paths.
## Provenance without eager instruction loading
The registry reads and hashes skill bodies and bundled resource bytes to bind source identity. It does not evaluate scripts, follow instructions in prose, or emit those bodies as model context. Discovery metadata and resource descriptors are separate from instruction loading. Future native carriers must preserve on-demand loading of selected skill bodies and required resources; this first slice implements no native loader.
| Digest | What it binds |
| --- | --- |
| Resource `digest` | Exact bytes of one source file |
| Entry `contentDigest` | Ordered resource descriptors, including paths, byte counts, and resource digests |
| `registryDigest` | Portable registry output, including inventory-source digests, ownership, metadata, and resource descriptors |
| `profileDigest` | Normalized profile manifest, with selection arrays sorted |
| `compilerDigest` | Source digests for the three compiler library files, two declaration schemas, and the existing install-manifest module supplying target IDs |
| `planDigest` | Complete portable proposed-plan object before adding `planDigest` itself |
These are SHA-256 content bindings, not signatures, runtime attestations, or a complete execution-environment identity. Digests deliberately exclude caller-specific absolute paths and timestamps. Equivalent selector ordering produces identical plans; changing a skill body changes provenance even when its discovery-metadata estimate stays constant.
## The 8K check is a metadata fixture gate
`estimate.surface` is `skill-discovery-metadata`. Method `utf8-bytes-div-4@1` renders each selected entry as canonical JSON containing `harness`, `type`, `name`, and `description`, adds a newline, divides UTF-8 bytes by four, rounds each entry up, and sums the results. The ledger exposes per-entry costs.
Lean rejects estimates above 8,000 using `CONTEXT_PROFILE_BUDGET_EXCEEDED`; a library caller can inspect the rejected proposal on `error.plan`. Exactly 8,000 passes the estimator check; 8,001 fails. Full uses the same reference budget in report-only mode.
This heuristic is an early rejection and regression fixture, not a tokenizer, measured lower bound, or whole-prompt certification. Passing cannot establish the production Lean startup ceiling. `nativeTokens`, `wrapperTokens`, and `wholeScopeTokens` remain `null` until appropriate observation exists.
The registry explicitly excludes agents, commands, rules, hooks, MCP schemas, harness wrappers, and learned skills. Skill bodies and bundled resources are hashed but excluded from the discovery estimate. Other plugin context, host overhead, repeated prompts, and task execution costs are also unmeasured. Report observed native counters separately and avoid deriving savings claims from this ledger alone.
## Target declarations are not runtime certification
The registry recognizes the current 15 install target IDs plus Pi. For a requested target, `projection.installSupport` reports `declared` or `not-declared` according to the owning module. `projection.nativeSupport` remains `unobserved` in both cases.
Target selection does not silently drop skills lacking an installer declaration. The same explicit skill selection is projected for every recognized target, so consumers can inspect gaps rather than mistake them for successful installation. Native discovery, invocation, resource access, reload behavior, exclusion enforcement, and whole-context cost require adapter-specific evidence in later slices.
## Rationale and alternatives
The read-only boundary makes the selection contract reviewable before it can alter user state. Versioned manifests and source digests provide shared inputs for adapters, grouping work, routing, and measurement. Keeping existing install ownership avoids a second independently maintained inventory.
Alternatives considered:
- Reuse install profile names for runtime scope. Rejected because installed files, visible context, hooks, and permissions are separate controls with existing compatibility obligations.
- Start by rewriting plugin caches or installed discovery files. Deferred until carrier ownership, fresh-session behavior, receipts, rollback, and user-edit preservation have evidence.
- Treat a task classifier or system prompt as the enforcement boundary. Rejected. Future agent proposals must be validated against deterministic contracts and retained consent.
- Infer complete workflow closure from Markdown prose. Rejected as an unreviewed authority source. Explicit declarations are auditable; the current dependency coverage remains incomplete.
- Declare 8K compliance from a character or byte estimate. Rejected. Metadata fixtures help catch regressions while native host measurements remain a separate gate.
## Contributor integration lanes
These related PRs are integration inputs, not claims that their proposed behavior has shipped. Preserve contributor attribution and verify each change against the shared contract before adoption.
| Contribution | Intended integration | Boundary |
| --- | --- | --- |
| [#2788](https://github.com/affaan-m/ECC/pull/2788) | Native discovery carriers and associated ownership/receipt work | Consume this registry and plan; carrier generation and activation belong to later slices |
| [#2844](https://github.com/affaan-m/ECC/pull/2844) | Catalog grouping, deterministic selection fixtures, and listing projection | Reuse canonical IDs and pack ownership instead of introducing competing profile authority |
| [#2945](https://github.com/affaan-m/ECC/pull/2945) | Task routing and automatic-selection proposals | Future structured task resolver; `selectionMode: "auto"` alone implements none of this |
| [#2740](https://github.com/affaan-m/ECC/pull/2740) | Native context counters and bounded diagnostics | Keep observed measurements separate from fixture estimates and scan assumptions |
| [#3030](https://github.com/affaan-m/ECC/pull/3030) | Contributor skill-quality validation | Content-quality checks complement inventory validation; they do not prove runtime activation or workflow outcomes |
| [#3032](https://github.com/affaan-m/ECC/pull/3032) | Existing js-yaml dependency security update | Verify contributor integration before release; retain both lockfiles and rerun dependency and regression checks |
The original September 8 dependency baseline pinned js-yaml 4.3.1, affected by [GHSA-2883-xcg3-v3hh](https://github.com/nodeca/js-yaml/security/advisories/GHSA-2883-xcg3-v3hh). PR preparation exposed that existing finding in hosted CI. This branch now includes Myles Agnew's exact 4.3.2 upgrade from #3032 as an attributed prerequisite commit, updating the runtime pin, overrides, resolutions, and both lockfiles. Runtime audit reports zero vulnerabilities after installation. The original contributor PR remains independently reviewable. This registry's `JSON_SCHEMA` excludes the advisory's merge behavior, but upgrading also protects existing default-schema parsers.
## Follow-on gates and verification
P2 now has resource-complete read-only carrier projections and disposable structural acceptance fixtures. Native fresh-session discovery and invocation remain unobserved. P3 adds transactional activation, receipts, ownership, migration, recovery, and rollback. P4 adds structured task selection, agent proposals, and bounded automatic routing. P5 integrates hook plans with explicit, separately retained consent. P6 earns release-default changes through package, operating-system, harness, compatibility, and recovery tests. None of those later stages is implied by a successful preview.
The first-slice checks live in [registry tests](../../tests/lib/context-pack-registry.test.js), [profile tests](../../tests/lib/context-profiles.test.js), [CLI tests](../../tests/scripts/profile.test.js), and the [context-profile validator](../../scripts/ci/validate-context-profiles.js). They cover source and selection validation, deterministic provenance, metadata boundaries, and read-only behavior. Those fixtures do not replace native fresh-session, activation, workflow, or whole-system measurement evidence.
In a source checkout, see the [TDD evidence record](context-profiles.tdd.md) and test files linked above for executed checks, checkpoints, coverage, and known gaps. Test sources and the evidence record are intentionally outside the reduced npm runtime surface.
+89
View File
@@ -0,0 +1,89 @@
# ECC-029 read-only context profile evidence
Date: September 8, 2026. Scope: the first P0/P1 implementation slice for M1, canonical context profiles. Baseline: main `5064474d4d762dc9640234a41617cccb79185cec`, ECC 2.2.1. Environment: macOS 26.6.2, Apple M4 Pro, Node 24.9.0. This is local development evidence, not a release or native-host certification.
Source intent: the accepted ECC-029 production and economics planning canvases in the maintainer workspace. Their approved first-slice journeys and boundaries are carried into the portable [implementation contract](context-profiles.md). Planning text was treated as design input; validation used reviewed local test, lint, package, and inspection commands. No activation, remote installer, publication, or credential-handling instruction was adopted. The project detector selected unavailable Bun; the actual test scripts run standalone Node, so Node and npm ran them without changing package-manager preferences.
## Journeys and test specification
| Approved journey and guarantee | Test target | Type | RED evidence | GREEN evidence |
| --- | --- | --- | --- | --- |
| Inspect versioned profiles and exact skill IDs without invoking skills or changing caller state | [CLI tests](../../tests/scripts/profile.test.js) | CLI journey/integration | `cd3950d3`: 24 failures for the missing command, entrypoint, and package inclusion | 25 passed, including later terminal-control regression; temporary home and workspace snapshots remain unchanged |
| Build one portable canonical skill inventory with validated ownership, explicit declarations, and resource digests | [Registry tests](../../tests/lib/context-pack-registry.test.js) | Unit/integration | `4c1b938b`: intended registry module absent | 15 passed, including source safety and repository inventory |
| Compile deterministic Lean/Full proposals with exact selectors, declared dependency closure, and honest metadata estimates | [Profile tests](../../tests/lib/context-profiles.test.js) | Unit/integration | `4c1b938b`: intended compiler module absent | 12 passed; 8,000 passes and 8,001 blocks the Lean metadata estimator, while native totals remain unknown |
| Gate every recognized target and register validation in the normal test workflow | [CI tests](../../tests/ci/context-profiles.test.js) | Integration | `5fcd9e08`: 3 failures for missing validation and registration | 3 passed; 2 profiles across 16 target IDs |
| Reject redirected source reads, unsafe metadata controls, and unstable cache-derived provenance | Registry and profile tests above | Security/regression | `f01d3366`: 23 passed and 3 expected failures during review | Same regressions pass; redirected descriptor receives zero byte reads in the substitution fixture |
| Keep user-supplied terminal controls inert in CLI error output | CLI tests above | Security/CLI | `254a6cc1`: 24 passed, 1 failed for raw OSC output | 25 passed |
| Ship the entrypoint, libraries, schemas, manifests, and contract together | [Publish-surface tests](../../tests/scripts/npm-publish-surface.test.js) | Packaging/integration | Existing explicit publish allowlist initially reported 1 pass and 1 failure | Updated expected public surface passes, plus real offline package smoke below |
The module-absence RED runs exercised the intended new public entry points; they were not failures of an unrelated dependency installation. The initial library checkpoint contained 20 cases; boundary and security review grew the focused library suite to 27. All listed checkpoints are local commits on `plan/ecc-029-harness-scoping`, reachable from the GREEN implementation commit. Preserve this record if later integration squashes those checkpoints. No separate refactor stage was performed after final GREEN validation.
## Executed checks
```sh
node --test tests/lib/context-pack-registry.test.js tests/lib/context-profiles.test.js
node tests/scripts/profile.test.js
node tests/ci/context-profiles.test.js
node tests/scripts/npm-publish-surface.test.js
npm run context-profiles:check
npm test
npm run lint
git diff --check
```
Final focused coverage execution also runs the first four feature test targets together:
```sh
./node_modules/.bin/c8 --all \
--include='scripts/lib/context*.js' \
--include='scripts/profile.js' \
--include='scripts/ci/validate-context-profiles.js' \
--reporter=text --reporter=json-summary \
--reports-dir=/tmp/ecc-029-context-coverage \
--check-coverage --lines=80 --functions=80 --branches=80 --statements=80 \
node --test tests/lib/context-pack-registry.test.js \
tests/lib/context-profiles.test.js tests/scripts/profile.test.js \
tests/ci/context-profiles.test.js
```
Results: 27 library cases, 25 CLI cases, and 3 CI cases passed. Node's outer TAP summary reports 29 because the CLI and CI files each wrap their own cases. New-code coverage is 98.43% statements and lines, 90% branches, and 100% functions. Coverage thresholds all pass; no focused cases were skipped. Uncovered lines include a defensive source-error path and the single-profile text rendering branch.
The complete `npm test` command exited 0 and its legacy aggregate reported `Total Tests: 4423`, `Passed: 4423`, `Failed: 0`. Its aggregate does not separately count the new node:test library cases, which have their explicit result above. Existing platform-dependent tests can skip on macOS; this run supplies no Windows or Linux execution evidence. Full ESLint/Markdown lint, catalog/command validators, and whitespace checks passed.
## Packed offline user journey
Ran `npm pack` with the real prepack build into a disposable directory, followed by `npm install --offline --ignore-scripts --omit=dev --no-audit --no-fund --userconfig=/dev/null` into a disposable consumer. The install succeeded using cached dependencies. No package was published or globally installed.
The packaged dispatcher produced Lean and Full Codex previews, and the packaged direct entrypoint explained an exact skill ID. Both full proposed-plan objects were deeply equal to their checkout counterparts, including registry, profile, compiler, and plan digests. The subprocess environment used an explicit allowlist and a disposable user-home path, which remained absent after all three calls. This checks the real archive and runtime dependencies independently of the checkout's module resolution.
At this baseline, Codex Lean selects 3 entries and leaves 283 routed; Full selects all 286. The descriptor estimator reports 221 tokens from 879 bytes for Lean and 26,145 tokens from 104,168 bytes for Full. These are reproducible fixture estimates, not observed native startup tokens or demonstrated task savings.
## Review findings and remaining gates
Independent review reproduced ancestor substitution and terminal-control issues before fixes, then rechecked the fixes and approved the read-only boundary. Source identity checks do not create an atomic filesystem snapshot. The initial checkpoint lacked an independent directory listing bound; the hosted-review follow-up below closes that gap. Dependency coverage remains explicit-declarations-only and unreviewed. Required-resource annotations need a distinct output contract before selective P2 carriers can safely omit resources.
The js-yaml integration prerequisite from contributor [PR #3032](https://github.com/affaan-m/ECC/pull/3032) is satisfied on this branch by the attributed 4.3.2 upgrade, fresh install, zero-vulnerability runtime audit and packed-consumer verification described below. Its original PR remains open; final hosted CI and release qualification are separate gates. See the [contract's dependency gate](context-profiles.md#contributor-integration-lanes).
Native carriers, active discovery, actual skill invocation, transactional activation, hook consent, automatic task routing, recovery, real-host token counters, broader context surfaces, cross-platform conformance, and default migration remain follow-on work. No provider calls, container or VM launches, or runtime profile changes were used to establish these results.
## PR-readiness follow-up
Independent exact-head review approved the read-only implementation and identified privilege-sensitive symlink fixtures. Review's original permission-denial injection produced 12 passes and 3 failures. Checkpoint `88f5a996` added a failing portable directory-link contract: 15 passes and 1 expected failure. The fix uses Windows junctions for directory cases, separates unconditional ownership and mocked leaf-link rejection from the real file-link integration case, and explicitly skips only that extra file-link case on Windows EPERM/EACCES. No runtime code changed.
Final local focused checks now pass 30 library, 25 CLI, and 3 CI cases. A bounded simulation of Windows file-link denial, keeping the local temporary directory fixed and emulating directory junctions, passes 17 registry cases and explicitly skips 1 real file-link case. It is a test-policy simulation, not native Windows evidence. The source-read substitution and zero-byte-read assertions remain mandatory.
An isolated Git archive passed `YARN_ENABLE_HARDENED_MODE=1 YARN_ENABLE_SCRIPTS=false yarn install --immutable --mode=skip-build`; both package manifest and Yarn lockfile remained byte-identical. The initially attempted immutable/update-lockfile combination was rejected by Yarn as incompatible before installation; the immutable skip-build run is the applicable successful CI check. Dependency declarations remain unchanged. Source-only evidence/test links in the shipped contract are now labeled explicitly.
### Contributor security prerequisite
Hosted CI for PR #3037 at `78cbd01c` reproduced the existing js-yaml high-severity advisory in its runtime audit. The branch incorporated contributor Myles Agnew's exact commit `5674661fc30ab1d3f3fcae22d72bfb4ab3059822` from #3032 using an attributed cherry-pick (`77872972`). No contributor PR was merged or closed. A fresh dependency install resolved js-yaml 4.3.2, and `npm audit --omit=dev --audit-level=high` reports zero vulnerabilities.
The local npm 11 install unexpectedly rewrote the Yarn lock into its legacy format. Only that task-induced rewrite was restored to the committed contributor bytes before subsequent validation. This is installation-tool behavior, not an intended lockfile change. The full test run started on the preceding revision overlapped the dependency update and is excluded from exact-final-head evidence; final PR checks must bind to the updated head.
### Hosted review regressions
The global dry-run parser regression was reproduced before implementation in `c373b7fe`: 27 CLI cases passed and 4 failed. Fix `9b5e3934` removes exact global `--dry-run` flags before command/value parsing, without mutating caller arguments or weakening other validation. All 31 CLI cases and seven independent parser probes pass. Both public entrypoints retain unobserved activation.
Checkpoint `ea00894d` adds seven source-reader regressions for incremental enumeration, the exact per-directory boundary, empty-directory breadth, excluded cache names, handle cleanup and directory identity changes. The corrected reader accepts at most 10,000 names per directory and charges every directory open and enumerated entry against a 20,000-operation reader budget, allowing one lookahead to detect overflow. It retains the file, cumulative-byte and depth bounds. Focused support/registry/compiler checks pass 37/37, including the mandatory ancestor-substitution test with zero redirected file-byte reads.
The source reader was split into focused helpers below 50 lines. Directory handles close in `finally`, and identities are revalidated before and after enumeration. Independent review checked that descriptor no-follow flags, identity checks before the first file byte, post-read checks and exact byte digests survive the extraction. This remains a bounded consistency check, not an atomic filesystem snapshot.
+1 -1
View File
@@ -377,7 +377,7 @@ cd ECC
| Qwen CLI | `./install.sh --profile minimal --target qwen` | [Qwen ガイド](../QWEN-GUIDE.md)を参照 |
| Hermes | `./install.sh --profile minimal --target hermes` | [Hermes セットアップガイド](../HERMES-SETUP.md)を参照 |
| OpenClaw | `./install.sh --profile minimal --target openclaw` | 管理されたホームディレクトリインストール |
| Kimi Code CLI | `./install.sh --profile minimal --target kimi` | プロジェクトローカルの `.kimi-code/` インストール · [Kimi Code を入手](https://www.kimi.com/code?aff=ecc) |
| Kimi Code CLI | `./install.sh --profile minimal --target kimi` | プロジェクトローカルの `.kimi-code/` インストール · [Kimi Code を入手](https://www.kimi.ai/code?aff=ecc) |
| CodeBuddy | `./install.sh --profile minimal --target codebuddy` | プロジェクトローカルの `.codebuddy/` インストール |
| JoyCode | `./install.sh --profile minimal --target joycode` | プロジェクトローカルの `.joycode/` インストール |