feat(check): fail on a copy of an issued rule (copyOf) - #423
Conversation
v2 reconcile marks an unknown rule that carries an issued rule's file with copyOf (taskless/taskless#262, #264). An sg or Vale copy no longer runs and fails check naming its source; when the source is also missing the pair is one rename naming `rule restore <source>`. Runtime copies are unchanged (never executed) but name the source. A malformed copyOf fails closed.
Picks up copyOf on reconcile's unknown rules (taskless/taskless#264), the revisions route (#261), whoami's per-org entitlements (#265), and EntitlementAnnotation on served sets (#260). All additive; copyOf is still read defensively, so nothing in the CLI changes.
ec85e40 to
863a920
Compare
|
@claude /review |
|
Claude finished @thecodedrift's task in 5m 9s —— View job Review mode: incremental — read 0 prior review thread(s) before reviewing.
AssessmentThis is a clean, well-scoped implementation. I traced Specifically verified, with no issues found:
I did not find a correctness, security, or test-coverage issue worth flagging inline. No inline comments posted. One thing I couldn't verify (noted per the review constraints, not treated as a gap): whether the vendored |
Thanks — no findings to address. On the one unverifiable point: the vendored — AI Coding Agent |
This closes the directory-rename hole in tamper detection. Copy an issued rule to a new id, loosen it, and delete the original: reconcile answered the copy
unknown(static rules run silently) and the originalmissing(a warning only), socheckpassed with a tampered rule running.The service now marks such an
unknownrule withcopyOf: { ruleId, revisionId, files }. It's proposed in taskless/taskless#262 and published in the v2 schema by taskless/taskless#264. This PR implements the CLI's side of it for 0.12.0.Behavior
unknownwithcopyOf: not run, removed from the snapshot, andcheckfails, naming the source rule and the differing files.missing: reported once, as a rename, namingtaskless rule restore <source>. There's no separate missing warning.copyOfthat is present but unreadable fails closed (unaccounted). The service sendscopyOfonly when it found issued content, so ignoring an unreadable one would run exactly the rule the field exists to stop.check --json:integritygains an optionalcopyOf: { ruleId, revisionId?, sourceMissing }, andengine.logrecords each copy.Notes
copyOf, the revisions route (taskless/taskless#261),whoami's per-orgentitlements(feat: publish how the corpus groups its fixtures, and what its paths are relative to #265), andEntitlementAnnotationon served sets (chore: publish the corpus as @taskless/cli/reference.json #260). All of it is additive.copyOfis still read defensively, sinceapplyVerdictsparses the reconcile answer by hand. feat(rule): list a rule's revisions, to choose one for rollback #422 also touches both generated files. A test merge of the two branches is clean, and the merged schema equals production's.unknown.check.mdgains "A copied or renamed rule", andrecover-rule.mdgets a sentence in Step 1), and one sentence in the pending 0.12.0 changeset.cli-copy-of-issued-rule, a single PR, archived here. The archive drops no existing scenario and adds six.Checks
pnpm typecheck,pnpm lint, andopenspec validate --all --strict(30) pass. The CLI suite passes: 112 files, 1,889 tests, including 9 new verdict cases and one end-to-end rename against the mock v2 reconcile.Refs taskless/taskless#255