Conversation
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.
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.
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.
#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
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.
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):What's in it (by theme)
change rewindexit code (01),--yesconfirmation gates (02), DDL identifier quoting (04),--helpbreadcrumbs (05),--jsondocs sweep + dead-surface removal (06), SDK/docs drift (07), dangerous-path tests (08), MIT license (27), headless config parity: honest exit-1 stubs + realconfig rm <name> --yesthrough the locked-stage guard (28), FK re-enable guarantee (03), SQLite rewind date-hydration crash (34), createDb SQLite flag (35),.dtzbad-path reader hang fix (41).attempt()+ native#privatein 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): unionedisVisibleToChannel+formatAccessTag..dtzxtest passphrase to satisfy 20's 12-char floor.UAT-discovered fixes (post-bundle)
--versionin compiled binaries reported0.0.0— dead literal, now wired to the build define../sql — 0 filesrow (42).run.buildignoredbuild.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-pgbuild include paths corrected to the documented sql-dir-relative contract.change rmwas ungated on all three surfaces (TUI even deleted the DB tracking record) — a viewer-role config could delete changesets. Newchange:rmpermission (deny/confirm/confirm), gated everywhere, spec + docs in lockstep (44).rewindhad no tiebreaker onappliedAt— same-second applies (routine underchange ff; structural on SQLite) reverted in dependency-violating order andrewind(name)could stop early. Tiebroken by history id (45).docs/spec/v1-*.mdimplementation 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/editnow exit 1 (were false-success 0);config rm <name> --yesdeletes headlessly, refusing locked-stage configs.NOORM_DEBUG=0now disables debug on all paths (previously enabled two of three).noorm run build(anddb reset's rebuild) now honorsbuild.include/exclude/rules like the TUI.change rmnow requires operator+--yesor admin+--yesheadlessly; viewer denied (was: no gate at all)..dtzpath now rejects promptly instead of hanging 15s+.Open questions filed as followups
config rmof the active config deletes silently (TUI courtesy-blocks) — needs a UX ruling.--no-fk/--no-identitynever worked (--no-Xnegation 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.