packages/agent/docs/work-packages/01-bound-values-lists.md
Complete. harness.md is normative. values.md supplies the detailed address, backend, and conformance design.
Replace the retained register/custom-state storage surface with bound Value<T> and ValueList<T> addresses across Session, Memory, JSONL, SQLite, instrumentation, tests, and public application access. Stop before runtime execution consumers.
pi.* namespace. Applications use their own non-reserved namespaces through the same public value() / list() constructors. fact.custom and its API are deleted, not renamed to a built-in custom namespace.pi.op.*, pi.pending.*, list, ledger, or arbitrary application address. A later application feature must add an address-specific fork policy before relying on copied application state.(namespace, key) as both a value and a list is a trusted-programming defect. Backends do not add cross-kind collision checks, triggers, registries, or catalogs.OperationMeta for immutable acceptance metadata and Operation for the process-local { meta: OperationMeta, state: OperationState } projection. operationMeta(id) binds Value<OperationMeta>; the composite is never persisted as one value.scanValues() returns key-ascending results. readList() limits only one query page, never total list length or bytes: reject non-positive or non-safe limits, default to 1,000, and clamp larger values to 10,000.SQLITE_STORAGE_VERSION = 1, edits 001_initial.sql in place, renames registers to scalar_values, and adds list_values. Pre-WP01 format-4 JSONL and SQLite files are unsupported. Add no migration runner or legacy decoder.Add packages/agent/src/harness/session/values.ts with:
Value<T> and ValueList<T> address types;value<T>(namespace, key?) and list<T>(namespace, key?) constructors;\u0000 component;StoredValue<T>, ListElement<T>, ListCursor, and ListReadOptions;setValue, deleteValue, appendList, and deleteList write helpers using NoInfer<T>;values.md.Replace the old API throughout:
getRegister(namespace, key) -> getValue(address)
listRegisters(namespace, prefix) -> scanValues(prefixAddress)
register set/delete writes -> typed value helpers
Storage and the historical Session reader, mutator, tree-view, and repository surfaces expose the same bound-address reads:
getValue<T>(address: Value<T>): Promise<StoredValue<T> | undefined>;
scanValues<T>(prefix: Value<T>): Promise<StoredValue<T>[]>;
readList<T>(address: ValueList<T>, options?: ListReadOptions): Promise<ListElement<T>[]>;
The historical tree-view and Session surfaces additionally expose one-commit direct writes:
setValue<T>(address: Value<T>, next: NoInfer<T>): Promise<void>;
deleteValue<T>(address: Value<T>): Promise<void>;
appendList<T>(address: ValueList<T>, element: NoInfer<T>): Promise<void>;
deleteList<T>(address: ValueList<T>): Promise<void>;
SessionMutator retains one explicit commit(writes) and does not gain direct committing methods. Each write array composes helper-constructed value/list writes with entries and usage.
Keep getName / setName and getLabel / setLabel as wrappers over sessionName and entryLabel(id). Delete getCustomFact / setCustomFact. Rename the public passive metadata event from fact_update to the value_update shape already specified by harness.md; it covers only session-name and entry-label wrappers, not arbitrary application writes.
packages/agent/src/harness/session/values.tspackages/agent/test/harness/values.test.tspackages/session-backends/sqlite-node/src/sqlite/session/values.tspackages/session-backends/sqlite-node/src/sqlite/session/registers.ts after moving its scalar behavior to values.ts;packages/agent/src/harness/session/types.ts.packages/agent/src/harness/agent-harness.tspackages/agent/src/harness/session/types.tspackages/agent/src/harness/session/commit.tspackages/agent/src/harness/session/storage-state.tspackages/agent/src/harness/session/memory.tspackages/agent/src/harness/session/session.tspackages/agent/src/harness/session/fork.tspackages/agent/src/harness/session/index.tspackages/agent/src/harness/session/jsonl/storage.tspackages/agent/src/harness/session/jsonl/repo.tspackages/agent/src/harness/session/testing/storage-decorator.tspackages/agent/src/harness/session/testing/instrumented-storage.tspackages/agent/src/harness/session/testing/types.tspackages/agent/src/harness/session/testing/conformance/storage.tspackages/agent/src/harness/session/testing/conformance/session-repo.tspackages/agent/src/harness/session/testing/benchmark/storage.tspackages/agent/src/harness/session/testing/benchmark/session-repo.tspackages/agent/src/harness/session/testing/index.tspackages/agent/src/harness/runtime2/restore.tspackages/agent/src/harness/runtime2/harness.tspackages/agent/src/harness/runtime2/lane.tspackages/agent/src/harness/telemetry.tspackages/agent/src/index.ts and packages/agent/src/node.ts only as needed to verify the new public exports; do not add a second export path.packages/agent/test/harness/memory-storage.test.tspackages/agent/test/harness/memory-conformance.test.tspackages/agent/test/harness/memory-session-repo.test.tspackages/agent/test/harness/jsonl-storage.test.tspackages/agent/test/harness/jsonl-storage-conformance.test.tspackages/agent/test/harness/jsonl-session-repo.test.tspackages/agent/test/harness/jsonl-session-repo-conformance.test.tspackages/agent/test/harness/storage-backed-session.test.tspackages/agent/test/harness/session-tree.test.tspackages/agent/test/harness/session-create-lane.test.tspackages/agent/test/harness/instrumented-storage.test.tspackages/agent/test/harness/types.test.tspackages/agent/test/harness/telemetry.test.tspackages/agent/test/harness/runtime2/harness.test.tspackages/agent/test/harness/runtime2/lane.test.tspackages/agent/test/harness/runtime2/restore.test.tspackages/agent/docs/telemetry-schema.mdpackages/session-backends/sqlite-node/src/sqlite/migrations/001_initial.sqlpackages/session-backends/sqlite-node/src/sqlite/repo.tspackages/session-backends/sqlite-node/src/sqlite/session.tspackages/session-backends/sqlite-node/src/sqlite/storage.tspackages/session-backends/sqlite-node/src/sqlite/index.ts if needed for the renamed modulepackages/session-backends/sqlite-node/test/storage.test.tspackages/session-backends/sqlite-node/test/storage-conformance.test.tspackages/session-backends/sqlite-node/test/repo.test.tspackages/session-backends/sqlite-node/test/adapter.test.tspackages/session-backends/sqlite-node/test/sql.test.tspackages/coding-agent/test/experimental-session-support.tspackages/coding-agent/test/experimental-remote-runtime.test.tspackages/coding-agent/test/experimental-server-replacement.test.tsIf the final old-API grep identifies another retained source/test call site, it belongs to WP01; do not add a compatibility shim to avoid touching it.
values.ts, export it through the existing session/root path, and add focused compile-time/runtime address tests. Include exact built-in namespace/key/kind tests and prefix-constructor tests before migrating callers.types.ts/commit.ts; split StorageState into current scalar values and surviving list elements; implement Memory reads/writes, ordered prefix scans, paged list reads, transaction validation/application, snapshots, and direct Session methods. Remove custom-fact APIs and migrate name/label wrappers.kind:"value" and kind:"list"; replay set/delete/append/delete; preserve transaction-line torn-tail atomicity; serialize surviving list elements with original seq merged in global sequence order; preserve the sequence high-water mark. This extends existing snapshot serialization only—do not add a new compaction trigger or precise-rewrite feature. Forks copy the fixed core set from Decisions item 2, re-sequence destination scalar values after copied entries as today, and copy no lists.restore.ts uses scanValues(branchTipInventoryPrefix()) plus exact getValue lookups and performs no readList() call. Do not add acceptance, drive, hydration, or cleanup behavior.001_initial.sql in place, implement scalar operations and indexed list append/delete/paging in session/values.ts, keep every write inside the existing BEGIN IMMEDIATE writer-lease transaction, update both fork snapshot paths, and retain all entry/usage/branch/lease behavior from current dev.fact_update to value_update. Keep the two remote prompt tests skipped for the existing WP00 reason; WP01 must not alter runtime execution.pi.session.write item kinds from register to value and list, regenerate telemetry-schema.md, run the old-API sweeps, and record any branch-policy-deferred changelog requirement. Do not edit a changelog on gramps unless it becomes a pull-request branch or the user requests it.seq;seq;Use:
CREATE TABLE scalar_values (
namespace TEXT NOT NULL,
key TEXT NOT NULL,
seq INTEGER NOT NULL,
value TEXT NOT NULL,
PRIMARY KEY (namespace, key)
) WITHOUT ROWID;
CREATE TABLE list_values (
namespace TEXT NOT NULL,
key TEXT NOT NULL,
seq INTEGER NOT NULL,
value TEXT NOT NULL,
PRIMARY KEY (namespace, key, seq)
) WITHOUT ROWID;
Ascending and descending list queries use the primary key with an exclusive sequence predicate and LIMIT. Add EXPLAIN QUERY PLAN assertions proving no table scan or temporary ordering b-tree. Do not change storage version, add migrations, or weaken the current lease/fence/fork behavior.
NoInfer rejects incompatible set/append values;\u0000 components reject;pi.* gate.seq;Do not add a value/list collision test: cross-kind misuse is intentionally an unenforced trusted-programming defect.
The following values.md requirements are explicitly not WP01 coverage:
getMemo / setMemo, tool-output checkpoint writes, outcome cleanup, and prefix-driven operation cleanup (R4/R6);WP01 still exports pendingAssistantFrames, operationToolMemo, pendingToolOutput, and every cleanup prefix so later packages do not redesign storage.
These must have zero matches in retained source/tests, excluding immutable released changelog history and archived prose:
rg -n 'getRegister\(|listRegisters\(|RegisterValues|RegisterNamespace|RegisterSetWrite|\bRegister<' \
packages/agent packages/session-backends/sqlite-node packages/coding-agent \
--glob '!**/dist/**' --glob '!**/CHANGELOG.md' --glob '!**/docs/**'
rg -n 'kind: "register"|getCustomFact\(|setCustomFact\(|fact\.(name|label|custom)|fact_update' \
packages/agent packages/session-backends/sqlite-node packages/coding-agent \
--glob '!**/dist/**' --glob '!**/CHANGELOG.md' --glob '!**/docs/**'
rg -n '"(branch\.tip|lane\.(config|state|lastResult)|op\.(meta|state|tool_args|preparation)|pending\.entry)"' \
packages/agent packages/session-backends/sqlite-node packages/coding-agent \
--glob '!**/dist/**' --glob '!**/CHANGELOG.md' --glob '!**/docs/**'
rg -n '\bregisters\b' packages/agent/src/harness/session packages/session-backends/sqlite-node/src \
--glob '*.ts' --glob '*.sql'
rg -n '"register"' \
packages/agent/src/harness/telemetry.ts \
packages/agent/test/harness/telemetry.test.ts \
packages/agent/docs/telemetry-schema.md
Do not treat unrelated model/provider/hook registration terminology as storage API residue.
Run each created or modified test file directly and iterate until green. At minimum:
# From packages/agent
node "$(git rev-parse --show-toplevel)/node_modules/vitest/dist/cli.js" --run \
test/harness/values.test.ts \
test/harness/memory-storage.test.ts \
test/harness/memory-conformance.test.ts \
test/harness/memory-session-repo.test.ts \
test/harness/jsonl-storage.test.ts \
test/harness/jsonl-storage-conformance.test.ts \
test/harness/jsonl-session-repo.test.ts \
test/harness/jsonl-session-repo-conformance.test.ts \
test/harness/storage-backed-session.test.ts \
test/harness/session-tree.test.ts \
test/harness/session-create-lane.test.ts \
test/harness/instrumented-storage.test.ts \
test/harness/types.test.ts \
test/harness/telemetry.test.ts \
test/harness/runtime2/harness.test.ts \
test/harness/runtime2/lane.test.ts \
test/harness/runtime2/restore.test.ts
# From packages/session-backends/sqlite-node
node "$(git rev-parse --show-toplevel)/node_modules/vitest/dist/cli.js" --run \
test/adapter.test.ts \
test/repo.test.ts \
test/sql.test.ts \
test/storage.test.ts \
test/storage-conformance.test.ts
# From packages/coding-agent
node "$(git rev-parse --show-toplevel)/node_modules/vitest/dist/cli.js" --run \
test/experimental-remote-runtime.test.ts \
test/experimental-server-replacement.test.ts
Then run from the repository root:
cd packages/agent && npm run check:telemetry-docs
cd "$(git rev-parse --show-toplevel)"
node_modules/.bin/tsgo --noEmit -p packages/agent/tsconfig.build.json
node_modules/.bin/tsgo --noEmit
git diff --check
npm run check
./test.sh
Never run unrestricted Vitest, npm test, paid-provider tests, or npm run build.
Stop when every retained backend and Session surface uses bound values/lists; all core addresses use the exact pi.* grammar; arbitrary application addresses work but generic forks exclude them; old register/fact/custom-state APIs and physical names are absent; base restore performs no list read; schema/compatibility decisions above are implemented; focused, conformance, TypeScript, telemetry-doc, diff, and repository checks pass. Report the final schema and fork behavior. Do not begin runtime acceptance, assistant/tool consumers, or any later work package.