Skip to content

feat(producer): rewire the conventions emitter, emit v0.4 (META-203) - #9

Merged
qmarcelle merged 1 commit into
mainfrom
feat/meta-203-conventions-emitter
Jul 26, 2026
Merged

feat(producer): rewire the conventions emitter, emit v0.4 (META-203)#9
qmarcelle merged 1 commit into
mainfrom
feat/meta-203-conventions-emitter

Conversation

@qmarcelle

Copy link
Copy Markdown
Contributor

a3fa85a deleted the conventions: expression and hardcoded specVersion: '0.3' — correct for v0.3, which had no conventions. The spec then moved to v0.4 and the producer was never rewired. The capability existed the whole time, disconnected from the path that matters.

The change

conventions: agentsMd.conventions
  .slice()
  .sort((a, b) => a.lineNumber - b.lineNumber)
  .map((c) => ({ raw: c.raw, type: c.type, canonical: c.canonical })),

plus specVersion: '0.3''0.4'.

The sort is load-bearing, not tidiness. conventions sits inside the material projection and stable() preserves array order — unstable ordering would make every run report drift and break generate --check as a CI gate. lineNumber gives a source-faithful order.

It wasn't two lines

WorkspaceJsonV3 declares specVersion: '0.3' as a literal, so emitting '0.4' required typing the artifact as WorkspaceJsonV4 throughout — GenerateResult, the drift comparison, the atomic writer, and the existing-artifact read.

I also checked the round-trip before writing v0.4: WorkspaceJsonValidator accepts v0.3, v0.4, and v0.4-with-conventions. Had it been v0.3-only, the next generate would have refused to overwrite its own output — a self-inflicted deadlock that would only have appeared on the second run.

Upstream type defect found

Published WorkspaceJsonV4['generated'] is Omit<V3['generated'],'specVersion'> & {…}. Because V3's generated block carries [key: string]: unknown, Omit collapses every named property into the index signature — so by, frameworkManifest and fileIndex are all unknown on V4 despite being typed on V3.

Worked around with one narrow cast in a test, documented at the site. Worth reporting to workspacejson/standard — it degrades the published v0.4 contract for every consumer, not just this repo.

The contract question was settled in advance, not assumed

docs/versioning.md defines v0.4 as a strict superset with optional new fields, and the published validator accepts the exact partial shape emitted here. So this has no sequencing dependency on META-235.

Parity — two new ratified differences

Both inspected before baselining. The gate refused them first, which is the point:

agents-audit generate --dry-run    specVersion 0.3 -> 0.4, + conventions
artifact-equivalence               same, on the written bytes

Verified the diffs are only those two lines. Producer stamp, manual preservation, refusal/--force behavior, exit codes, and the console output of generate, generate --check and generate --force are all unchanged. Recorded in migration/parity-expected-differences.txt citing META-203; gate green at 4/4.

Verification — R-1 through R-9

R-1  red observed FIRST: conventions ABSENT, specVersion 0.3
R-2  green: conventions present, specVersion 0.4
R-3  shape exactly {raw, type, canonical}
R-4  validates against published @workspacejson/spec@0.4.4
     (spec CLI exit 0; validate() and validateV4() both true)
R-6  coChange/fragility still absent — correct, optional in v0.4
R-7  manual sentinel survived regeneration verbatim
R-8  determinism: two runs 3s apart — conventions AND hygiene byte-identical,
     second run reports no drift, --check exits 0
R-9  parity gate green with the two recorded differences

typecheck 3/3 · build 3/3 · tests 85 (35 + 44 + 6)
architecture guard pass · red tests 19/19 · packs verified

R-8 also closes the temporalWeight determinism concern raised on META-195: generated.hygiene was byte-identical across a real delay, so the rules engine's time decay is not reaching the score.

Two things deliberately not done

No ADR. Checked against docs/adr/README.md's required list — this touches none of the five items. conventions and specVersion: '0.4' are already in the shipped schema, which is why this is a rewire rather than a contract change. META-235 will need one; that's noted on it.

No committed artifact. R-5 said "regenerate and commit the honest result" — but that referred to the forged artifact in workspace-json/agents-audit, which is frozen and must not be modified. This repo has never committed a .agents/workspace.json. Adopting one — and removing the || true that currently neuters CI's self-check — is a separate decision with ongoing maintenance cost, so it is not bundled here.

Nothing published.

`a3fa85a` (2026-05-13) deleted the `conventions:` expression from the generated
block and hardcoded `specVersion: '0.3'`. Correct for v0.3, which had no
conventions. The spec then moved to v0.4 and the producer was never rewired —
the built-not-wired class: the capability existed and was disconnected from the
path that matters.

The change

  conventions: agentsMd.conventions
    .slice()
    .sort((a, b) => a.lineNumber - b.lineNumber)
    .map((c) => ({ raw: c.raw, type: c.type, canonical: c.canonical })),

plus specVersion '0.3' -> '0.4'.

The sort is load-bearing, not tidiness. `conventions` sits INSIDE the material
projection and `stable()` preserves array order, so unstable ordering would make
every run report drift and break `generate --check` as a CI gate. `lineNumber`
gives a source-faithful order.

Not two lines: the emitted type had to move too

WorkspaceJsonV3 declares `specVersion: '0.3'` as a literal, so emitting '0.4'
required typing the artifact as WorkspaceJsonV4 throughout — GenerateResult,
the drift comparison, the atomic writer and the existing-artifact read.

Verified before writing v0.4 that the round-trip is safe: `WorkspaceJsonValidator`
from @workspacejson/rules accepts v0.3, v0.4 and v0.4-with-conventions. Had it
been v0.3-only, the next `generate` would have refused to overwrite its own
output.

Upstream type defect found and worked around

Published `WorkspaceJsonV4['generated']` is
`Omit<V3['generated'],'specVersion'> & {...}`. Because V3's generated block
carries `[key: string]: unknown`, `Omit` collapses every named property into the
index signature — so `by`, `frameworkManifest` and `fileIndex` are all `unknown`
on V4 despite being typed on V3. One narrow cast in a test, documented at the
site. Worth reporting to workspacejson/standard: it degrades the published v0.4
contract for every consumer, not just this repository.

Contract question settled in advance, not assumed
docs/versioning.md defines v0.4 as a strict superset with optional new fields,
and the published validator accepts the exact partial shape emitted here
(`validate` and `validateV4` both true, spec CLI exits 0). So this has no
sequencing dependency on META-235.

Parity — two new ratified differences, both inspected before baselining
  agents-audit generate --dry-run   specVersion 0.3->0.4, + conventions
  artifact-equivalence              same, on the written bytes
Verified the diffs are ONLY those two lines. Producer stamp, manual
preservation, refusal/force behavior, exit codes, `generate`, `generate --check`
and `generate --force` console output are all unchanged. Recorded in
migration/parity-expected-differences.txt citing this issue; gate green at 4/4.

Verification (R-1..R-9)
  R-1 red observed first: conventions ABSENT, specVersion 0.3
  R-2 green: conventions present, specVersion 0.4
  R-3 shape exactly {raw,type,canonical}
  R-4 validates against published @workspacejson/spec@0.4.4 (CLI exit 0,
      validate() and validateV4() both true)
  R-6 coChange/fragility still absent — correct, optional in v0.4
  R-7 manual sentinel survived regeneration verbatim
  R-8 determinism: two runs 3s apart, conventions AND hygiene byte-identical,
      second run reports no drift, --check exits 0
  R-9 parity gate green with the two recorded differences
  typecheck 3/3, build 3/3, tests 85 (35 + 44 + 6), guards 19/19 red tests

R-8 also closes the temporalWeight determinism concern raised on META-195:
`generated.hygiene` was byte-identical across a real delay, so the rules
engine's time decay is not reaching the score.

Nothing published. R-5 note: this repository has never committed its own
.agents/workspace.json, and adopting one (plus removing the `|| true` that
currently neuters CI's self-check) is a separate decision, not bundled here.
Copilot AI review requested due to automatic review settings July 26, 2026 15:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@qmarcelle
qmarcelle merged commit c4a58d3 into main Jul 26, 2026
3 checks passed
@qmarcelle
qmarcelle deleted the feat/meta-203-conventions-emitter branch July 26, 2026 15:17

@charliecreates charliecreates Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the v0.4 producer change, including convention projection/order, existing-artifact validation and drift behavior, and the frozen agents-audit parity baseline. No blocking issues found. CI is green on Node 20 and 22, including the compatibility-parity job.

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.

2 participants