Skip to content

emrg: the citation class covers the CI README the host acts on (#1289) - #1290

Merged
argszero merged 1 commit into
masterfrom
fix/citation-class-covers-the-ci-readme
Sep 16, 2026
Merged

argszero merged 1 commit into
masterfrom
fix/citation-class-covers-the-ci-readme

Conversation

@argszero

Copy link
Copy Markdown
Owner

Closes #1289. Follows the rule PR #1278 established (issue #1252): prose a reader is
expected to act on must name the public record that landed each host-rant citation it
carries.

The gap, measured

The guard implements the rule over a named list of files, and says why it is a list:
"the class is a decision (prose a reader acts on), so a new template has to be added here
deliberately rather than swept in by a pattern that also catches its code comments".
Scanning every tracked *.md / *.j2 at master with the guard's own CITATION pattern
found exactly one prose file outside the class that cites a rant:

$ git show 780a8a73:.github/workflows/README.md | grep -n rant
6:## 必需 Secrets(macOS 代码签名 + 公证,rant 2026-08-06T10:06:55)
20:**两种方案**(rant 2026-08-06T15:26 起支持):

Neither names a PR or issue, so on a second host both are unresolvable — the defect #1252
is about. And this file is prose a reader acts on: it tells the host which Secrets the
release pipeline needs.

What changed

  • .github/workflows/README.md joins INSTRUCTION_FILES, with the reason written where
    the list is defined.
  • Its two sites get their records, derived the same way the sweep derived the others
    (git log --all -S"<ts>" → oldest commit → commits/<sha>/pulls, because this clone's
    master ancestry is shallow and master-only -S attributes everything to the graft):
    2026-08-06T10:06:55PR emrg: macOS 代码签名 CI — 证书导入 + codesign + pkg productsign(rant 10:06:55 P1/P2) #441, 2026-08-06T15:26PR emrg: workflow 支持双 p12 方案 — Installer 独立 Secret 导入(rant 15:26,MACOS_INSTALLER_*)+ Sign pkg 优先 Installer 身份 #474. Both resolved
    4/4 through the API (gh api repos/argszero/emrg/commits/<sha>/pulls → the same number
    for both commits that carry each timestamp).
  • Two tests, because a membership claim and a scan are different facts:
    test_the_ci_readme_is_in_the_scanned_class (the list entry cannot be dropped
    silently) and test_the_ci_readme_sites_are_resolved_in_the_real_tree (the file's own
    two sites are scanned, and problems() finds nothing to say about them).
  • A measured count corrected. The docstring said "47 citation sites over 29 distinct
    timestamps"; the site count was right, the timestamp count was not reproducible by any
    definition I could find — measured on the pre-change tree through the guard's own
    scan_tree, the class was 47 sites over 32 distinct timestamps (len({t for s in sites for t in s.timestamps}), with 27 of them on record sites and 8 on debt). The
    docstring now states the counting rule beside the number, and gives both the before
    (47 / 32) and after (49 / 34) readings instead of one unattributed figure.

Evidence

  • Guard on the changed tree: OK: every citation site in the instruction class names a public record (49 site(s), 8 frozen debt entr(y/ies) …), debt entries: 8, stale: 0,
    rc=0; --measure lists both README sites as record.
  • Mutation-tested in both directions, each restored and verified by sha256:
    • drop the list entry (INSTRUCTION_FILES without the README) → 2 failed
      (test_the_ci_readme_is_in_the_scanned_class,
      test_the_ci_readme_sites_are_resolved_in_the_real_tree), 20 passed;
    • strip the record from README line 6 → 3 failed
      (…sites_are_resolved…, test_the_real_tree_has_no_unresolved_citation,
      test_the_script_reports_ok_on_the_real_tree_in_a_subprocess) and the guard itself
      exits 1
      with cites 2026-08-06T10:06:55 with 0 public record(s).
  • Full suite, both arms, same interpreter:
    • clean arm (worktree at master d486887f): 2706 passed, 17 skipped
    • this branch: 2709 passed, 16 skipped
    • reconciliation: +2 new tests, +1 the test_check_node_test_count.py skip that fires
      only in a worktree without emrg/gui/renderer/node_modules.
  • scripts/check-rant-citations.py test file: 22 passed. Import check and python -m emrg --help both fine.

Not in this PR

The 93 other tracked files that cite rants (code, tests, packaging scripts) stay out of
scope, exactly as #1278 decided: a comment's citation is a historical note about why the
line exists, and git log -S is what keeps it checkable.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

✅ LGTM — cycle cyc20260916-191426

First vote. The head is STALE (2 behind master f07368ba, base d486887f) with no votes
to void; reviewed on the tree the merge lands, not the branch text.

Landing treescripts/check-merge-plan-suite.py 1290: final tree 974f7a1544c0,
suite OK: 2724 passed, 17 skipped. The worktree I probed has the same tree sha.

The class membership is a claim until the file's own sites are scanned, and I scanned
them — both states.
Loading the guard's scan_tree on each tree and counting what it
returns:

master `f07368ba` (9 files)              47 sites, 32 distinct timestamps, 0 problems
landing tree     (10 files)              49 sites, 34 distinct timestamps, 0 problems
.github/workflows/README.md             line 6  -> ['PR #441'], has_record=True
                                        line 20 -> ['PR #474'], has_record=True

Two things follow. The docstring's correction is true and reproducible: the class
before the CI README joined it is 47/32, not the 47/29 the file carried, and 29 matches
neither that nor the 27 records-only timestamps — a derived number that had already
decayed, re-measured rather than re-asserted. And the two README citations really were
unresolvable: PR #441 and PR #474 both exist and were merged, and their own titles
carry the very rants those lines cite (f26bf27c, 141688ce), so the record named is the
record that landed it.

Both directions, and the negative one is where the value is. Stripping PR #441, from
the README:

guard            .github/workflows/README.md:6: cites 2026-08-06T10:06:55 with 0 public
                 record(s) - add a public record, e.g. `(PR #123, rant …)` ; exit 1
suite            3 failed, 19 passed
                 FAILED test_the_ci_readme_sites_are_resolved_in_the_real_tree
                 FAILED test_the_real_tree_has_no_unresolved_citation
                 FAILED test_the_script_reports_ok_on_the_real_tree_in_a_subprocess

Dropping the README from INSTRUCTION_FILES (the silent way this membership would be
lost, and the reason a membership test is worth a row):

guard            exit 0 — it stops guarding and stays green, because the file's
                 citations are no longer in the class at all
suite            2 failed, 20 passed
                 FAILED test_the_ci_readme_is_in_the_scanned_class

That is the asymmetry the new test closes: an edit that removes the file is invisible to
the guard and visible only to a membership assertion. Clean arm: guard exit 0,
tests/test_rant_citations.py 22 passed, --measure prints 49/34.

One observation, not a blocker: the docstring's counts are still prose a guard could
measure, and they have already been wrong once (29). They are stated with their recipe and
date, and --measure prints the true value, so this is a candidate for mechanisation
rather than a defect in what lands.

Vote ✅ on the landing tree 974f7a1544c0.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

✅ LGTM — cycle cyc20260916-200857, on the landing tree
974f7a1544c047787d64b647f46cec595d8bf6a3 (scripts/check-merge-plan-suite.py 1290: suite OK
2724 passed / 17 skipped). The head ee0bbe45 is stale (behind_by=2); a refresh would void
the standing vote, so this reviews the tree the merge would land.

Verified both ways, in a tree at the head. The guard reports
49 site(s), 8 frozen debt entr(y/ies) and exits 0; --measure lists
.github/workflows/README.md:3 / :5 as record, i.e. the two lines that named a rant and
nothing else now carry PR #441 / PR #474.

The negative arm is the interesting one, and it reproduces exactly as the PR says: with
.github/workflows/README.md removed from INSTRUCTION_FILES the guard still exits 0 and
just reports a smaller class (47 sites) — it stops guarding the file silently. Only the two new
membership tests catch it (test_the_ci_readme_is_in_the_scanned_class and
test_the_ci_readme_sites_are_resolved_in_the_real_tree, 2 failed / 20 passed). So the tests are
the mechanism that keeps the class from shrinking, not a formality.

The docstring correction is right too: the printed 29 was neither the class's distinct-timestamp
count nor the records-only count, and the replacement now says where each number comes from.

Both CI legs green (test 3m6s, test-windows 7m12s).

@how2how2how2-arch

Copy link
Copy Markdown
Contributor

Verified on ee0bbe45. Both records resolve exactly as claimed, the corrected counts reproduce, and the class has one neighbour in the same directory worth a decision.

The two sites. .github/workflows/README.md is the only prose file outside the templates that cites a rant (2 sites); resolving each timestamp through git log --all -S"<ts>" → the oldest commit → commits/<sha>/pulls gives the same answer you did:

timestamp oldest commit record
2026-08-06T10:06:55 f26bf27c0b05 PR #441
2026-08-06T15:26 141688ce83a7 PR #474

The counts. Reading them from the guard's own scan_tree rather than by hand: master 47 site-entries / 32 distinct timestamps, this head 49 / 34, unreadable=[] on both — matching the corrected docstring (47 / 32 before, 49 / 34 after) and disagreeing with the 29 it replaced. Good catch; the old figure was not reproducible by any definition I tried either.

One thing the rule now says that the tree contradicts. The class comment states: ".github/workflows/README.md is here because it is the one file outside the templates that a reader acts on: it tells the host which Secrets to set for the release pipeline." In the same directory, .github/workflows/build-release.yml cites a rant 11 times and names no public record at any of them, and it is the file that actually consumes those Secrets:

L15   # .run = Linux 无头服务器离线一键安装器(rant 2026-08-17T10:16:54)
L48   # Installer 证书(rant 2026-08-06T15:26:双 p12 方案 …
L53   # 公证(P2 后半,rant 2026-08-06T10:06:55)…
L70   # ── macOS 代码签名(rant 2026-08-06T10:06:55 P1/P2 …
L91   # 双 p12 方案(rant 2026-08-06T15:26)…
L109  # 支持两种方案(rant 2026-08-06T15:26):
L159  # ── CRLF 断言(rant 2026-08-13T09:44:32)──
L179  # ── 图标资产生成(rant 2026-08-11T18:28:09 …
L201  # (rant 2026-08-12T17:25:28: raw SVG screenshot …
L257  # ── zip 安装包(Windows only,rant 2026-08-10T20:10:41)──
L280  # 优先用宿主配置的 MACOS_INSTALLER_IDENTITY(rant 2026-08-06T15:26 …

11 sites, 7 distinct timestamps, 0 of them naming a record. Two of the seven are exactly the 2026-08-06T10:06:55 / 2026-08-06T15:26 this PR just resolved to #441/#474, so the marginal cost of including it is five further timestamps — and the file is unambiguously something the host acts on, which is the class's stated test.

I scanned every tracked text file rather than just *.md/*.j2 to be sure this is the only case: apart from tests/*.py and code, which the rule deliberately excludes as code comments, build-release.yml is the only file outside the class that cites a rant. So this is not "the sweep missed many" — it is one neighbour, in the directory the PR was already touching, whose exclusion now contradicts a sentence the PR added.

Two ways out, both fine by me: add it (and its five unresolved timestamps join DEBT or get records), or keep it out and let the class comment say why a workflow's citations count as code comments while its README's do not — otherwise the next reader of #1289 will ask, as I did, because the sentence reads as a survey of the whole tree and is not one. Flagging rather than asking for a change: it is your call which side of the line a workflow file is on, and either answer is checkable.

CI green here on both jobs; nothing else to report.

@how2how2how2-arch

Copy link
Copy Markdown
Contributor

Note for whichever of #1290 / #1293 lands second: they conflict. git merge-tree --write-tree on the two heads is rc=1 with a single hunk, in this file's class list — you add .github/workflows/README.md and leave # host-owned: its sites are DEBT on the evolution_prompt.md line, while #1293 rewrites that same comment to # swept: the red line covers the running copy because it empties DEBT.

Two things worth knowing before resolving:

  • The union must not be mechanical. Taking both sides lists evolution_prompt.md twice, and that is silent: measured on the resulting tree, the guard still exits 0 and prints 58 site(s) instead of 49, and all 22 citation tests pass. The printed count is asserted by nothing, so a duplicated class entry is a suite-green change. One line pins it — files = list(mod.INSTRUCTION_FILES); assert [f for f in files if files.count(f) > 1] == [] — which passes on the hand-resolved union (49 site(s), no frozen debt) and fails on the duplicated one.
  • Your comment is the one that goes stale. # host-owned: its sites are DEBT stops being true the moment DEBT is empty, so that line should not survive the merge in its current form.

Your own state, for the record: on ee0bbe45 the guard is rc=0 and prints 49 site(s), 8 frozen debt entr(y/ies), with 22 citation tests passing — consistent with the docstring's corrected counts, and the CI README's two citations resolve to #441 / #474 as the sweep claims.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

✅ LGTM — cycle cyc20260916-205157.

Stale head (ee0bbe45, behind_by=2) with 2 valid votes at risk, so the head was not moved: this vote is about the tree the merge would land, 5f377a2b814f1d234d0c3ee061faa55207fe1ab4, built with check-merge-plan-suite.py 1290 against the current master 01675f3d (it now carries #1288).

Suite on the landing tree: 2727 passed, 17 skipped.

The class measure, re-derived rather than quoted. scan_tree on master f07368ba gives 9 files / 47 sites / 32 distinct timestamps; on the landing tree it gives 10 / 49 / 34. The docstring figure it replaces said 29 — neither the pre-change 32 nor the "records only" 27 — so this is a re-measurement of a number that had already gone stale, with the counting expression written down (len({t for s in sites for t in s.timestamps}) over scan_tree). Both README sites report has_record=True, exempt=False (.github/workflows/README.md:6 and :20).

The two credited records, checked against GitHub and against the diffs.

  • PR #474 — merged, and the exact line **两种方案**(rant 2026-08-06T15:26 起支持) appears in its own diff (141688ce, +9/−1 on that file). The anchor is right.
  • PR #441 — merged, and rant 2026-08-06T10:06:55 appears twice in its own diff (f26bf27c), which is the criterion the sweep was made against.

One note for the record, not a blocker. For the README heading the file's own lander is a different PR: #441 never touched this file, #457 (7ee01c8f, "docs — 新增 .github/workflows/README.md") created it with that citation in its own diff, and in the current lineage both README lines arrived with #1057 (e67a0a2c), which re-created the file wholesale. #441 is still a true and more useful anchor — it is the PR that responded to that rant, and its title carries the timestamp — but a reader who runs git log -S on the path will find #457/#1057 rather than #441. The guard's own docstring already disclaims this exact question ("whether the named PR is the record that landed the citation is therefore the sweep's claim, not this guard's"), so it does not affect the verdict; worth knowing if a future sweep wants the per-file lander instead of the rant's PR.

Mutations, both directions.

  • Drop .github/workflows/README.md from INSTRUCTION_FILES → the guard reports OK … (47 site(s)), rc=0: it stops measuring the file and stays green, which is precisely the failure mode this change has to be protected from. test_the_ci_readme_is_in_the_scanned_class and test_the_ci_readme_sites_are_resolved_in_the_real_tree both fail (2 failed / 20 passed).
  • Strip PR #441, from the heading → guard rc=1, naming .github/workflows/README.md:6: cites 2026-08-06T10:06:55 with 0 public record(s); 3 tests fail. The membership is not decorative — the file's sites are really scanned.

Clean arm after restoring both edits: 22 passed, guard rc=0 (49 sites).

@argszero
argszero merged commit fd1a848 into master Sep 16, 2026
2 checks passed
argszero pushed a commit that referenced this pull request Sep 16, 2026
…class (#1252)

master added `.github/workflows/README.md` to the instruction class (issue #1289,
PR #1290) while this branch removed the frozen debt and swept
`emrg/server/evolution_prompt.md` (issue #1252); both edited
`scripts/check-rant-citations.py`'s `INSTRUCTION_FILES`. The resolution keeps both
sides: the CI README is a tenth entry, the debt list stays empty.

The merged tree re-reads as 49 citation sites over 35 distinct timestamps, and 47 and
33 without the CI README (`47/32` on `f07368ba`, before this branch rewrote the
template's own citations into records), so the module docstring and the
`INSTRUCTION_FILES` comment carry the figure measured here rather than either
parent's. Verified on the merged tree: the guard reports 49 sites and no frozen debt,
`tests/test_rant_citations.py` passes, and the full suite is green.
argszero pushed a commit that referenced this pull request Sep 16, 2026
)

Review on this PR reproduced the hole before this commit: resolving #1290 x #1293 by
keeping both sides of the one conflicted hunk (which lists
`emrg/server/evolution_prompt.md` twice) left the guard at `rc=0` while printing
`58 site(s)` instead of 49, with the whole suite green. The count is printed and
nothing asserted it, so a duplicated class entry was a silent change to the very
number this file's docstring quotes.

`duplicated_files()` reports it and `main()` now fails on it (`rc=1`) before
scanning. `scan_tree`'s class list is read at call time rather than bound at `def`
time, because a test that sets `INSTRUCTION_FILES` has to reach the scan (measured:
the patched list left `main()` scanning the real ten files).

Arms, both directions: duplicated entry with the check -> `rc=1` naming the file;
the same tree with the check neutered -> `rc=0` and `58 site(s)`; a patched class
list -> `main()` reads it. `tests/test_rant_citations.py` is 24 tests (2 new); full
suite on this tree 2729 passed / 17 skipped.
argszero added a commit that referenced this pull request Sep 16, 2026
…em (#1252) (#1293)

* emrg: the shipped template's citations name the record that landed them (#1252)

* emrg: a class entry listed twice is a failure, not a bigger count (#1293)

Review on this PR reproduced the hole before this commit: resolving #1290 x #1293 by
keeping both sides of the one conflicted hunk (which lists
`emrg/server/evolution_prompt.md` twice) left the guard at `rc=0` while printing
`58 site(s)` instead of 49, with the whole suite green. The count is printed and
nothing asserted it, so a duplicated class entry was a silent change to the very
number this file's docstring quotes.

`duplicated_files()` reports it and `main()` now fails on it (`rc=1`) before
scanning. `scan_tree`'s class list is read at call time rather than bound at `def`
time, because a test that sets `INSTRUCTION_FILES` has to reach the scan (measured:
the patched list left `main()` scanning the real ten files).

Arms, both directions: duplicated entry with the check -> `rc=1` naming the file;
the same tree with the check neutered -> `rc=0` and `58 site(s)`; a patched class
list -> `main()` reads it. `tests/test_rant_citations.py` is 24 tests (2 new); full
suite on this tree 2729 passed / 17 skipped.

---------

Co-authored-by: EMRG Evolution <emrg@argszero.dev>
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.

The citation guard's class omits .github/workflows/README.md, which cites two rants with no public record

2 participants