Skip to content

feat: Align open-monitor with @hasna/contracts - #7

Merged
andrei-hasna merged 4 commits into
mainfrom
factory/45101057-07b2-4d9e-8961-e2c525d2-d60aaca3
Jul 30, 2026
Merged

feat: Align open-monitor with @hasna/contracts#7
andrei-hasna merged 4 commits into
mainfrom
factory/45101057-07b2-4d9e-8961-e2c525d2-d60aaca3

Conversation

@andrei-hasna

@andrei-hasna andrei-hasna commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Objective

Align open-monitor with @hasna/contracts

Run the @hasna/contracts conformance check for this repo and fix every violation until it passes — ensure a valid hasna.contract.json, published_artifact_gate satisfied (artifact-scan wired into prepack), storage waiver where applicable, and all required metadata/scripts present. Keep changes minimal and conformant. Open a PR; do not merge.

Verification

  • policy source: base 448932f (immutable commit — agent-proof)
  • ⚠️ GATE-INTEGRITY: agent touched verify-bearing config — REVIEW (scripts.artifact-scan, scripts.contract-check, scripts.prepack)
  • containment: env — allowlist env, non-login shell, run-scoped HOME (registry auth seeded for install)
  • install: pass
  • typecheck: pass
  • lint: pass
  • build: pass
  • test: pass
  • doctor (ci): ok — 11 checks passed (1 advisory)

Run run_d037ca5a5af7 · backend codewith · task 45101057-07b2-4d9e-8961-e2c525d27b5a
🏭 Generated by @hasnaxyz/factory


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Align open-monitor with @hasna/contracts

Run the @hasna/contracts conformance check for this repo and fix every violation until it passes — ensure a valid hasna.contract.json, published_artifact_gate satisfied (artifact-scan wired into prepack), storage waiver where applicable, and all required metadata/scripts present. Keep changes minimal and conformant. Open a PR; do not merge.

X-Factory-Run: run_d037ca5a5af7
X-Factory-Task: 45101057-07b2-4d9e-8961-e2c525d27b5a
The hasna.contract.json added in this branch matched no schema: every
top-level key was invented, so `contracts repo-conformance .` failed at
manifest_valid and the repo was no more contract-aligned than before.
Rewrite it in the real hasna.service_contract.v1 shape — schema, name,
class, contractVersion, kitVersion, bins, hosting, serviceSurfaces and
storage.

The `prepack` script also broke publishing. `contracts artifact-scan`
requires a packed .tgz and the script passed none, so it exited 1 and
took `npm pack`, `bun pm pack` and `npm publish` down with it — an
already-published package became unreleasable. Pack the tarball inside
the gate instead, with --ignore-scripts so prepack does not recurse, and
declare the script through metadata.release.artifactScan.

`contract-check` named `contracts check`, which the CLI does not expose;
point it at `repo-conformance` and pin the kit version so the gate is
reproducible. The pin now lives once, in kitVersion.

Nothing exercised any of this, and the repo had no CI at all. Add
src/contract.test.ts over the manifest shape, the bin allowlist and the
gate wiring — including a pack that reproduces the prepack abort — plus
a ci workflow running typecheck, tests, the contract gate and the pack.
Six of the ten new tests fail against the previous commit.

Two gaps stay open and are recorded in the manifest rather than hidden:
the monitor-server and monitor-web bins fall outside the contract bin
allowlist and cannot be renamed without a breaking change to a published
package, and PostgresAdapter busy-waits with Bun.sleepSync so every
query deadlocks, which is why postgres is waived rather than declared.
…check

Two reviewer findings on the first-ever CI workflow for this repo.

1. `bun test` was red on the GitHub runner, so the workflow turned main's
   board red and the two gates it exists to add never ran.

   Root cause is the pre-existing timeout probe in
   src/collectors/command.test.ts, which ran `sleep 30 & wait`. `wait` with no
   operands always exits 0, so whenever the backgrounded job dies early the
   shell exits 0 immediately and the probe degenerates into "a shell ran" —
   `result.ok` comes back true and the timeout is never exercised. That is
   reproducible locally: with a PATH the login profile leaves without `sleep`,
   the old command returns {code:0,signal:null,timedOut:false} in ~48ms,
   matching the runner's 0.18ms failure exactly.

   The probe now blocks in the foreground, using shell builtins only, so
   neither `wait`'s exit status nor a login profile's PATH can hollow it out. A
   background holder is still started, so a kill that reaches only the direct
   child leaves a grandchild holding the stdio pipes and defers `close` — the
   test still fails when `killChildTree` drops its negative-pid kill. A
   negative control pins "exited 0 before the deadline" as distinct from
   "killed on the deadline", which is the distinction the old assertion
   collapsed, and the failing path now dumps the whole result instead of
   reporting only "Expected: false, Received: true".

   The gates also now run before the suite, so one red test cannot skip them
   again, and src/contract.test.ts asserts that ordering.

2. `bun run contract-check` — the authority — still exits 1 on
   bins_match_package, and nothing in the repo or CI ran it. The kit ignores
   metadata.contractAlignment.pendingBinRenames, and contract-gate is
   deliberately weaker at exactly that point, so a green board sat over a
   non-conformant repo.

   scripts/contract-baseline.ts runs the authority and holds it to an explicit
   baseline declared in the manifest. It passes only when the failing set is
   exactly {bins_match_package: monitor-server, monitor-web}: a new failure, a
   drifted detail, or a baseline entry that stops failing all break the build,
   as does output with no verdict lines, so the gate cannot pass vacuously if
   the kit changes its report format. CI runs it as its own step.

   The bin resolution itself is unchanged — dropping monitor-server and
   monitor-web is a breaking change to a published package and remains an owner
   decision, now recorded as an enforced deferral rather than an invisible one.

Verified: 299 pass / 0 fail / 725 expect across 27 files (bun test); lint,
contract-gate --online, contract-baseline, scan:artifact and npm pack --dry-run
all exit 0. Adding a third undeclared bin makes contract-baseline exit 1.
Corrects the root cause of the red CI in the previous commit, which named the
wrong one. The diagnostics added there paid for themselves immediately: the
runner reported

  ok:true, exitCode:0, durationMs:1, timedOut:false,
  stdout:"1 0 root Ss 0.1 1024 120 init /sbin/init\n100 1 root R 2.3 ..."

That stdout is `fakePsOutput` from src/collectors/local.test.ts. No shell ever
ran. local.test.ts calls `mock.module("./command.js", ...)`, which rewrites the
registry for the whole `bun test` process, and bun binds each file's imports as
it loads that file — so the stub reached every file loaded afterwards.
src/collectors/command.test.ts imports the same "./command.js", so whether its
timeout probe tested the real function or a canned stub came down to bun's
directory iteration order: this repo's suite was green on one machine and red on
the runner for that reason alone, and running the file on its own always passed,
which is why the flake looked environment-specific.

Restoring the module in `afterAll` does not work — measured: the afterAll runs,
and bindings already made are unaffected. So the stub moves to the class seam
instead. `collect()` reaches the shell only through the public
`LocalCollector.runCommand`, so a `StubShellLocalCollector` subclass overriding
that one method gives local.test.ts what it needs with no registry mutation and
no change to product code.

command.test.ts gains the tripwire that was missing: it now asserts the
command's own stdout comes back, which a canned stub cannot fake. Every
ok/exitCode/timedOut assertion in that file was satisfiable by the stub, which is
why the leak went unnoticed.

The previous commit's rewrite of the timeout probe stands on its own merits —
`X & wait` really does exit 0 whenever the backgrounded job dies early, since
`wait` with no operands always returns 0, reproduced locally at
{code:0,signal:null,timedOut:false} in ~48ms with a `sleep`-less login PATH — but
it was not what CI was failing on.

Verified: reproduced the CI failure locally by giving the probe file a name bun
loads after local.test.ts (2 fail, identical payload to the runner), then 0 fail
with this change. Full suite 299 pass / 0 fail / 726 expect across 27 files;
lint, contract-gate --online, contract-baseline, scan:artifact and
npm pack --dry-run all exit 0. Run 30515066588 already showed Contract gate,
Conformance baseline and Pack succeeding on the runner with Test the only
failure.
@andrei-hasna
andrei-hasna merged commit c4cbd1e into main Jul 30, 2026
2 checks passed
@andrei-hasna
andrei-hasna deleted the factory/45101057-07b2-4d9e-8961-e2c525d2-d60aaca3 branch July 30, 2026 05:19
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