Skip to content

v1 audit: integrated worklist (45 tickets, full CI green)#47

Draft
damusix wants to merge 227 commits into
masterfrom
next
Draft

v1 audit: integrated worklist (45 tickets, full CI green)#47
damusix wants to merge 227 commits into
masterfrom
next

Conversation

@damusix

@damusix damusix commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

v1 readiness audit — integrated worklist

Integrates 45 verified tickets from the v1 audit (tickets/v1/ in the realm repo) onto one branch. Every ticket was implemented TDD-first, gated by an independent reviewer, and separately verified (live-DB where relevant). This branch was then re-verified as a whole:

Full CI on the merged result — all green (@ a4e55d2):

  • Group 1 (utils+core+sdk): 2545 pass / 0 fail
  • Group 2 (transfer): 122 pass / 0 fail
  • Group 3 (cli): 418 pass / 0 fail
  • Group 4 (integration, live pg/mysql/mssql): 627 pass / 0 fail
  • typecheck / build / build:packages: clean

What's in it (by theme)

  • v1-blockers: SDK failure contract → throw named errors (25), change rewind exit code (01), --yes confirmation gates (02), DDL identifier quoting (04), --help breadcrumbs (05), --json docs sweep + dead-surface removal (06), SDK/docs drift (07), dangerous-path tests (08), MIT license (27), headless config parity: honest exit-1 stubs + real config rm <name> --yes through the locked-stage guard (28), FK re-enable guarantee (03), SQLite rewind date-hydration crash (34), createDb SQLite flag (35), .dtz bad-path reader hang fix (41).
  • Cleanups / conventions: dead deps+domain purge (09), @logosdx/utils adoption (10), validation single-source + secret-key gap (11), TUI/RPC helper adoption (12), inert-param + DT-seam deletion (13), SDK type hardening (14), last try-catch → attempt() + native #private in state/lock managers (15), binary checksum verification (16), change-retry resume-from-failed-file (17), test-db guard (18), lazy CLI startup ~4x (19), secret-file hardening (20), repo hygiene + release-engine docs (21+31), trim unused surfaces (22), formatting/voca consolidation (23), polish batch: ConflictStrategy reuse, one NOORM_DEBUG truthiness rule, camelCase citty args, MCP stack-leak removal (24), error-doc alignment (26), observer relocation → noormObserver (33), hooks-order fix (36), field follow-ups (39, 40), SDK-boundary live-DB throw-contract coverage (38).

Merge-conflict resolutions (3)

  • manager.test.ts (08↔34): kept 08's comprehensive suite, un-skipped the two #34-deferred rewind tests (now valid with 34's fix).
  • types.ts (07↔25): took 25's throw-contract JSDoc.
  • policy/index.ts (12↔23): unioned isVisibleToChannel + formatAccessTag.
  • Plus one integration fix: bumped a dt .dtzx test passphrase to satisfy 20's 12-char floor.
  • The final four (15/24/28/41) merged conflict-free.

UAT-discovered fixes (post-bundle)

  • --version in compiled binaries reported 0.0.0 — dead literal, now wired to the build define.
  • Run dir picker rendered a phantom ./sql — 0 files row (42).
  • SDK/CLI run.build ignored build.include/exclude/rules entirely — headless build now matches the TUI's effective file set, preserving runBuild's discovery-failure contract (43).
  • examples/llm-memory-db-pg build include paths corrected to the documented sql-dir-relative contract.
  • Policy bypass: change rm was ungated on all three surfaces (TUI even deleted the DB tracking record) — a viewer-role config could delete changesets. New change:rm permission (deny/confirm/confirm), gated everywhere, spec + docs in lockstep (44).
  • rewind had no tiebreaker on appliedAt — same-second applies (routine under change ff; structural on SQLite) reverted in dependency-violating order and rewind(name) could stop early. Tiebroken by history id (45).
  • Per-ticket docs/spec/v1-*.md implementation contracts removed (42 files) — audit trail lives in the realm repo; the five inbound references made self-contained.

Known behavior changes (for UAT)

  • config add/edit now exit 1 (were false-success 0); config rm <name> --yes deletes headlessly, refusing locked-stage configs.
  • NOORM_DEBUG=0 now disables debug on all paths (previously enabled two of three).
  • Headless noorm run build (and db reset's rebuild) now honors build.include/exclude/rules like the TUI.
  • change rm now requires operator+--yes or admin+--yes headlessly; viewer denied (was: no gate at all).
  • Bad .dtz path now rejects promptly instead of hanging 15s+.

Open questions filed as followups

  • Headless config rm of the active config deletes silently (TUI courtesy-blocks) — needs a UX ruling.
  • Pre-existing citty quirk: --no-fk/--no-identity never worked (--no-X negation collision) — behavior unchanged by this PR; followup filed.

Full per-ticket detail, evidence, and decision memo: tickets/v1/ + research/v1-audit/ in the realm repo.

damusix added 30 commits July 12, 2026 03:59
README advertised MIT while all three manifests said ISC and no
LICENSE file existed (VR-hyg-01; D3 ruled MIT). Copies in cli/sdk
so both npm tarballs ship the license text.
'partial' (some reverts failed) exited 0 with an info-level summary,
so CI proceeded past a botched rewind. Match sibling batch commands:
status !== 'success' exits 2 with an error-level log, per the
documented headless contract.
SDK JSDoc, tutorials, example README, and skill file referenced
APIs that never existed (ctx.exportTable, ctx.reset, noorm/sdk
imports, db create --name, noorm help). v1-audit VR-api-03,
VR-docs-02/03/04/05.
Unescaped names from config could break out of the identifier and
inject DDL against system databases (QL-sec-01). Names now route
through dialect quoting; config save rejects quote, bracket, and
semicolon characters in server-dialect database names.
All zero-reference per v1 audit (AP-dead-01/03/05/06, AP-yagni-01,
QL-sec-03, QL-xrepo-02). Spec: docs/spec/v1-09-dead-purge.md.
A mid-truncate failure skipped the enable-FK bookend, leaving MSSQL's
per-table NOCHECK persistently off. Enable statements now always run;
the original error still surfaces. TransferResult gains
fkChecksRestored so a swallowed FK restore failure is visible in
CLI/JSON output. (QL-safe-01, QL-safe-05)
--yes never reached checkProtectedConfig, so operator-role configs
failed headless despite the documented flag. Threads yes through
CreateContextOptions and unifies NOORM_YES truthiness in isEnvTruthy.
A misconfigured TEST_* env var pointed the destructive integration
suite at whatever it resolved to. Non-test-looking database names now
fail before any statement runs (QL-safe-06).
Plaintext-credential exports and the encrypted state file landed at
umask default (0644, world-readable). chmod-after-write mirrors
saveKeyPair: covers platforms where writeFile mode is unreliable and
fixes pre-existing files. QL-sec-05, QL-sec-06.
Agents can connect/disconnect but had no way to check what they're
currently connected to. Adds a read-only status command returning
connected configs and the active config, giving hasConnection/
listConnections their production callers (closes AP-yagni-06, D9).
Bare --passphrase flag leaked via ps/shell history and accepted
1-character passphrases. Adds MIN_PASSPHRASE_LENGTH (12) enforced on
encrypt only, and a masked @clack/prompts fallback when the flag is
omitted on a TTY; --passphrase remains the documented CI escape hatch.
Eager discoverFiles threw on a missing sql dir where runBuild
resolves a failed BatchResult — db reset crashed to exit 1.
@damusix damusix changed the title v1 audit: integrated worklist (41 tickets, full CI green) v1 audit: integrated worklist (43 tickets, full CI green) Jul 13, 2026
damusix added 8 commits July 13, 2026 02:21
Deleting an applied change also removes its DB tracking row, so
admin gets confirm (not allow) — same posture as config:rm and
db:destroy. Closes the v1-44 UAT policy bypass at the model layer;
TUI/CLI/SDK gates follow.
Mirrors ChangeRevertScreen's checkConfigPolicy + SmartConfirm pattern.
Viewer is denied outright; operator/admin both hit the confirm cell
(deleting an applied change also drops its DB tracking row).
Mirrors config rm: viewer denied before any prompt, operator/admin
confirm via --yes/NOORM_YES (isYesMode), no TTY prompt substitute.
Also fixes NOORM_YES not being honored by the old ad-hoc confirm.
Mirrors apply/revert/ff/rewind checkProtectedConfig call shape.
Admin is not frictionless here (confirm cell, not allow) since
deleting an applied change also drops its DB tracking row.
@damusix damusix changed the title v1 audit: integrated worklist (43 tickets, full CI green) v1 audit: integrated worklist (44 tickets, full CI green) Jul 13, 2026
damusix added 8 commits July 14, 2026 02:43
Implementation-time contracts; the durable audit trail lives in the
realm repo (tickets/v1, research/v1-audit). The five inbound
references were made self-contained. config-access-roles.md stays —
matrix.ts cites it as source of truth.
appliedAt is second-precision and ties are routine (change ff applies
several changes in one process tick). The unbroken sort preserved
list() insertion order on ties, reverting oldest-first and truncating
rewind(name)'s slice early. Break ties on the history row's
autoincrement id, the only true apply-order key.
A comment-rewrite regex in b971f2f over-matched and swallowed the
whole test. Restored un-skipped — the v1-45 tiebreak is its fix.
@damusix damusix changed the title v1 audit: integrated worklist (44 tickets, full CI green) v1 audit: integrated worklist (45 tickets, full CI green) Jul 14, 2026
damusix added 10 commits July 25, 2026 03:07
#48)

* fix(cli): skip binary download in source checkout

postinstall pins its download to the release tag matching packages/cli's
version. In the monorepo that tag is routinely not a published release,
and tags cut before the release workflow began emitting checksums.txt
have nothing to verify against. Verification failure is a hard failure by
design, so `bun install --frozen-lockfile` died on every CI run since
alpha.39 -- before lint, typecheck, or a single test.

Nothing in the repo consumes the download: CI builds the CLI from source
and wraps dist/index.js on PATH. Skip it when the private workspace root
is found two levels up, which the npm tarball never ships, so consumer
installs keep downloading and verifying unchanged.

* style(test): wrap overlong jsdoc to satisfy max-len

Pre-existing 203-char line failing eslint max-len. Only surfaced once
`bun install` stopped failing first and CI reached the lint step.

* fix(example): make mssql build includes relative to paths.sql

build.include resolves under paths.sql now, so `sql/00_types` expands to
sql/sql/00_types and matches nothing. The pg example was migrated to bare
segments; mssql was missed, so its build ran zero files, reported success,
and left the schema uncreated -- `change ff` then failed on a missing
dbo.Tag. Mirrors examples/llm-memory-db-pg/.noorm/settings.yml.
Six issues from one production MSSQL migration. Four share a shape:
a documented contract with no plumbing behind it, failing silently at
exit 0. Traces pin each root cause; spec carries the checkpoints.
citty forwards only the argv slice after the subcommand token, so a
flag typed before it was dropped with no error and exit 0. Docs showed
that form, and the #49 reporter used it.

-c/--cwd is the only root-level flag -- it is consumed before dispatch,
and -c already means --config at leaf level, so moving it would
collide. Every other flag before the subcommand is now rejected naming
the correct form rather than ignored.

The placement guard previously watched for the --json form; retargeted
to the flags that are actually position-bound.

Refs #49, #52
Both commands documented --dry-run but never declared it, so the flag
was a silent no-op and a dry-run build applied every file -- 307
objects into an empty database in the field report. The core gate
already worked; only the wiring was missing.

db teardown also reported 'Dropped N objects' under --dry-run while
dropping none.

Closes #49
db create and db drop read the stored config record raw, so
NOORM_CONNECTION_* was ignored and CI created a database named by
whatever config happened to be checked in. Route both through the
canonical resolver, as every other connecting command already does.

Closes #51
change list/history wrote their table through the logger, which sends
non-json output to stderr -- so a non-interactive shell saw nothing
and exit 0, indistinguishable from an empty database. In --json mode
the routing was inverted instead, putting event NDJSON on stdout ahead
of the payload and forcing consumers to tail -1.

Results now go to stdout and the event stream to stderr, in both
modes, and an empty result set prints an explicit empty-state line.
lock status and db explore carried the same defect.

Two integration tests asserted the result on stderr, pinning the bug.

Closes #52
change add left change/ and revert/ empty, so parseChange rejected the
changeset and change run reported it as not found -- for a change that
exists. Scaffold 001_<slug>.sql stubs in both.

The empty-content check compared against one hard-coded template
string; any other wording slipped through and ran as a silent no-op.
Generalize it to any non-blank, non-comment line.

Closes #53
$.secrets was a plain object and sqlQuote stringified undefined, so a
missing secret rendered as the literal 'undefined' and applied -- the
field report created a login whose password was those nine characters.
It is now a Proxy that throws naming the key, and sqlQuote rejects
undefined while still mapping null to NULL.

Separately, buildSecretsContext implements the documented three-tier
precedence and docs/dev/vault.md names it as the render path, but it
had no production caller: the render path used getAllSecrets,
config-local only. Vault secrets reached no template, for any
identity. Render contexts now go through it.

Resolving the vault tier must not cost offline commands their offline
guarantee, so run preview and run inspect probe with a single attempt
and no backoff, and say so when the tier could not be consulted.

Optional probing is now 'KEY in $.secrets' -- ?? evaluates the read
that throws, and silently accepting a missing secret is the coercion
this fixes. One example template updated.

Closes #50
createFileRecords inserts a pending row per file before the loop, and
needsRun read newest-by-id -- so it always found the current run's own
pending row and declared every file new. Checksum skipping has been
structurally dead for run build/dir/files since the initial release,
while two doc pages promised it. That is why a second build against a
populated database fails on the first non-idempotent DDL, which is
what #54 was filed as. Exclude the current operation from the lookup.

No double-execution mechanism exists -- ruled out at kysely, tedious,
tarn, discovery, filter, and the execution loop. Add the invariants
that make any recurrence self-diagnosing instead: reject duplicate
discovered paths, assert one result per file, fail updateFileExecution
on a multi-row match, distinguish a read error from a new file, report
prior successful executions on failure, and log the resolved host,
port, and database on connect -- the ambiguity #51 created.

Refs #54
noorm secret was undocumented in the CLI reference while the dev
secrets page claimed the command did not exist and sent users to
'vault set' instead -- the misdirection behind #50. Adds
docs/cli/secret.md with an explicit tier table, and corrects the dev
page, which contradicted both the code and its own user guide.

Also: change add's real output shape, the NNN_ layout and ordering
that #53 asked for, the stdout/stderr contract from #52, the in-guard
now required for optional secret reads, and flag placement throughout.

Refs #49, #50, #52, #53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant