okf: path-scoped ingest + status porcelain (ADR-001/002) - #57
Open
indexzero wants to merge 2 commits into
Open
Conversation
…set (ADR-001) auto-okf ingest <vault> <bundle> [paths…]: optional trailing bundle-relative paths restrict the one-shot scan to exactly those concept files, so one agent's ingest never sweeps up another writer's mid-write pending file. All named paths are validated before any op is appended (all-or-nothing): a path that does not exist, resolves outside the bundle root, or is not a .md file exits 1 naming the path, zero ops appended. Zero paths = full scan, unchanged. Judgment calls: literal paths only — the ADR permits globs, but paparam's rest capture is plain strings and the shell already expands globs, so an in-process matcher would only add a second, subtly different glob dialect; a named non-.md path (or directory) errors rather than being silently skipped, since silent skips of explicitly named paths are the confusion this ADR exists to kill. paparam's rest is greedy (once both positionals fill, remaining flags land in rest), so cmdIngest re-recognizes --confirm-deletes/--help there to keep the pre-ADR flag-last forms working. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…in (ADR-002)
auto-okf status <vault> <bundle> [--json]: one <state>-TAB-<path> line per
.md file in the union of {planned projection, emission manifest, disk},
sorted by path; --json emits the same rows as a stable [{ path, state }]
array (the schema is contract, kept to exactly those two fields). Strictly
read-only: no ops appended, no files written, no manifest touched — status
never even mkdirs a missing bundle dir (the new faces status() skips
rootRegistry for that reason).
The states are judged against the exact bytes materialize would write:
materialize's plan steps 1-4 are extracted into planBundle(vault), shared
by materialize and status, so nothing is reinvented. Mapping, from the
strictest reading of the ADR table plus the ingest watcher's own
classification as the pending-ingest/dirty tiebreaker:
- in-log: on-disk bytes hash-match the current planned projection.
- dirty: manifest-tracked (so the concept is in the log) but bytes
diverge from the projection — either a hand edit the watcher would fold
in as diffs against the existing concept (it hashes against the
manifest, not the plan), or a log that moved past the last materialize.
- pending-ingest: untracked hand-authored file the watcher WOULD establish
a concept for (same non-empty-type gate as IngestWatcher._fmType).
- absent: planned but missing from disk (materialize would restore).
- foreign: untracked and not establishable (e.g. a mid-write WIP with no
parseable type) — ingest will not put it in the log as it stands.
Derived faces (index.md/log.md) are part of the projection and report
in-log/absent/dirty like any planned file; a manifest entry with neither a
file nor a projection is retired state and gets no row.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
PR 3 of the ADR stack (base: #56, which bases on #54). The two concurrent-writer features, one commit each:
auto-okf ingest <vault> <bundle> [paths…]restricts the scan to the named bundle-relative paths. Nonexistent, outside-root, directory, or non-.mdnamed paths error by name with exit 1 and zero ops appended — a mixed good+bad argument set aborts all-or-nothing (silent skips of explicitly named paths are the confusion these ADRs exist to kill). Zero-path form unchanged. Literal paths, not an in-process glob engine: the shell already expands globs, and a second subtly-different glob dialect is a new confusion source.auto-okf status <vault> <bundle> [--json]: read-only per-file porcelain with a fixed five-state vocabulary —in-log,pending-ingest,dirty,absent,foreign— derived from the same projection plan materialize uses (aplanBundleextraction fromfaces/lib/materialize.js, so status can never disagree with what materialize would do).--jsonis a sorted array of exactly{ path, state }; human form is<state>\t<path>lines matching thewanted/flagsstyle. Appends no ops, writes no files, touches no manifest — asserted byte-for-byte in tests.The headline regression test is the confusion log's own incident, now pinned: a file swept into the log by a separate spawned CLI process reports
in-log, notpending-ingest— the case that previously required readingingest.jssource to diagnose.Verification
pnpm test:okf→ 135/135;pnpm test(full repo) → 250/250; cli.test.js 13 → 18 testscmdIngest)--jsonbyte-stable across consecutive runs,dirtyandabsentcoveredNotes for review
pending-ingest/dirtytiebreak follows the ingest watcher's own semantics (documented in the commit body):dirty= manifest-tracked but diverged from the current projection;pending-ingest= untracked file the watcher would establish (same non-empty-typegate);foreign= untracked and not establishable. Derived faces (index.md/log.md) participate as in-log/absent/dirty.status(ADR-002 defers it — one command, one question).