653f95e39f7338d08e04f7620c366fe49ce1dfd0
12 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
653f95e39f |
chore(#2801): remove the hostBehaviors.reviewerCli deprecated alias (#3272)
* test(#2801): failing-first suite for the hostBehaviors.reviewerCli alias removal Inverts the Phase 5a rows that assert the derived legacy alias still contributes a reviewer slug, and adds the removal-warning coverage the alias's exit needs (ADR-2782 D9). RED against unmodified production code, by design: the six shipped manifests still declare the key and collectReviewerWarnings emits nothing for hostBehaviors. Refs #2801 * chore(#2801): remove the hostBehaviors.reviewerCli deprecated alias ADR-2782 D9, Phase 7 — the final phase of epic #2782. The derived legacy alias survived one release (Phase 5a shipped in 1.9.0; 1.9.1 and 1.10.0 have since gone out), so it goes. A declared reviewer body is now the only route onto the reviewer roster. - deriveReviewerSlugs no longer reads runtime.hostBehaviors.reviewerCli - the key is stripped from the six manifests that carried it; each already declares a reviewer body whose slug equals its capability id, so the derived roster is unchanged at the same twelve slugs - collectReviewerWarnings emits a presence-based, non-fatal removal notice for any manifest still declaring the key, reaching both the build-time registry generation and the third-party overlay load path. The check runs before the reviewer-body early-return, because the manifest it exists for is the alias-only one that has no body. - hostBehaviors stays an open, unvalidated bag for its other 59 keys; this adds one keyed removal notice, not general validation Refs #2801 * refactor(#2801): give the reviewer-warning channel a typed IR Review finding: the new tests asserted with String#includes() on the warning prose, which CONTRIBUTING.md's 'Prohibited: Raw Text Matching on Test Outputs' bans in favor of a typed intermediate representation. Adds the IR beside the renderer rather than replacing it, which is the shape that section prescribes and bin/verify-reapply-patches.cjs already models: - REVIEWER_WARNING, a frozen code enum - REMOVED_REVIEWER_CLI_FIELD, so the emitting site and its test share one symbol instead of duplicating a literal - collectReviewerWarningRecords(cap), returning typed records collectReviewerWarnings(cap) keeps its exact string[] contract as a thin map over the records, so both production consumers are untouched. Every section-K row now asserts on record.code/field/capId and none on the rendered message. Locks the code surface, asserts the renderer stays one-to-one with the records, and migrates the pre-existing Phase 2 test on the same channel off prose matching. Refs #2801 * test(#2801): invert the section F alias fall-through regression row Caught by the remote runner: 2 unique failures on both Node lanes out of 31,692. tests/reviewer-lane-declarations.test.cjs section F — Phase 5a's isolated-security-review regressions — asserted that a blank reviewer.slug falls through to the hostBehaviors.reviewerCli alias rather than dropping the lane. That is the direct inverse of this phase's contract. The original rationale held only while the alias existed. With it gone there is nothing to fall through to: a blank body is not a declaration, and a declaration is the only route onto the roster. Inverted rather than deleted — the row carries the adversarial-review provenance for the slug trim, and removing a security regression guard to make a change pass is backwards. The duplicate row added earlier in section C is dropped instead; section F is its canonical home. Also corrects two count strings Phase 5b left at eleven while asserting twelve, which would misreport on failure. Refs #2801 * docs(#2801): give the removed reviewerCli flag a migration path The Reference edit alone satisfied CI — a file under docs/ moved, so lint-docs-required.cjs was green — while the task-oriented quadrant said nothing about the removal. A maintainer whose lane had just gone silent would have found the field documented as removed and no page telling them what to do about it. Adds a migration section to the how-to: the symptom, the verbatim warning they will see, the before/after manifest, and the note to keep the reviewer slug equal to the capability id so existing review.default_reviewers entries and --<slug> flags survive. Refs #2801 * chore(#2801): backfill changeset pr number to 3272 * feat(#2801): close the runtime.hostBehaviors vocabulary ADR-1016 closes twelve descriptor axes and rejects an open escape hatch in the descriptor. It never mentioned runtime.hostBehaviors, and that silence was read as permission: 59 keys across 18 manifests, 39 of them set by a single capability, validated by nothing. The reference docs went further and attributed the open seam to ADR-1016, which does not mention the field at all. KNOWN_HOST_BEHAVIORS enumerates the vocabulary. An undeclared key yields a non-fatal UNKNOWN_HOST_BEHAVIOR record on the same D4.3 channel as the alias removal notice, reaching both build-time generation and overlay install. Warning, never error, for the reason this phase exists: an error would hard-break an out-of-tree descriptor carrying a bespoke key with no deprecation window, which is what reviewerCli was given a release to avoid. Escalation is a separate decision. reviewerCli is excluded from the unknown-key sweep so it keeps its own notice with the migration pointer rather than drawing two records. A parity test binds the vocabulary to the shipped manifests in both directions, and a second asserts no shipped capability draws a notice, so the closure is provably inert in-tree. Records the decision and the miscitation as an ADR-1016 amendment. Refs #2801 * fix(#2801): bound and sanitize the unknown-key diagnostics Two findings from an isolated adversarial review of the closure commit, both proven by execution rather than asserted. MAJOR, introduced by the closure: the new Object.keys(hostBehaviors) sweep had no ceiling. An installed third-party manifest is bounded only by MANIFEST_MAX_BYTES, and an 8.69MB manifest with 800,000 keys produced 800,000 records and ~139MB of message text, retained for the registry's lifetime in OverlayMeta.diagnostics. Now capped at ten records plus a summary carrying omittedCount, mirroring capability-loader's existing slice(0,3) idiom. The same manifest now yields 11 records and 1748 chars. MINOR, newly reachable: manifest-supplied key names were interpolated raw. Unlike cap.id, which validateCapability gates on KEBAB_RE before these diagnostics run, hostBehaviors keys have no grammar check anywhere, so ANSI escapes and CRLF reached stderr and OverlayMeta.warnings intact. New describeKey replaces C0/C1 controls and clips at 80 chars. The file already had describeValue for this and applied it only to values. Both fixes land on the pre-existing reviewer.* sweep too — it carried the identical pair, and fixing only the new copy would leave the same defect one screen from its own fix. Refs #2801 --------- Co-authored-by: sim <sim@local> |
||
|
|
f96cb44f85 |
enhance(#3248): disclose capability skills as an instruction surface (#3253)
* test(#3248): failing-first suite for instruction-surface disclosure 28 matrix rows from 50-test-matrix.md. Rows requiring the new Disclosure.instructionSurfaces field fail today; rows 18-20/23-25 (the ADR-2363 D4 signature invariants) pass today by construction because the current code never reads skills/agents at all, and stand as regression guards for the implementation commit. Refs #3248 * feat(#3248): disclose capability skills and agents as an instruction surface ADR-2363 D5. A capability whose only contribution was skills disclosed nothing at install: summarizeDisclosure early-returned "ships no executable surfaces (declarative only)" because hasExecutable was false, while each SKILL.md body landed verbatim in the agent's instruction context. discloseExecutableSurfaces gains a fifth, NON-executable class, instructionSurfaces, collecting declared skills/agents stems through the same safeCollect wrapper as the four existing collectors, so a hostile value degrades only this class and the function stays total for any manifest shape. Nothing existing is edited: the collectors, hasExecutable, disclosureSignature and missingArtifacts are untouched. get_impact rates the symbol CRITICAL at 196 affected, which is why the design is strictly additive. D4 is implemented by omission and pinned rather than left incidental: adding, changing or removing skills/agents leaves disclosureSignature byte-identical, so no stored consent record is perturbed and no spurious re-consent fires. ADR-2782's conditional-append trick is deliberately NOT reused - it worked because no manifest could declare a reviewer body before that class existed, whereas skills predate this one, so a conditional append would re-sign every already-consented skill-bearing capability. The renderer is extracted as summarizeInstructionSurfaces and called from BOTH branches of summarizeDisclosure. Appending only at the end would never render for skill-only capabilities - the ones that need it - since those take the early return. That branch's "declarative only" claim is now conditional on there being no instruction surface either. The renderer iterates rather than spreading into push, so an unbounded stem count cannot throw RangeError, and tolerates the bare {} the CLI edge passes via `res.disclosure || {}`. Scope note: #3248's prose says "skill stems"; ADR-2363 D3 classifies instruction surfaces as "skills, agents". Shipping skills alone would leave an ADR deliverable owned by no phase, and the epic has no Phase 2. Agents are the same shape at no extra cost. Narrowing back is a two-line change. Ratifies ADR-2363 (Proposed -> Accepted) and adds the owed ADR-1244 back-link. Closes #3248 * fix(#3248): escape consent-prompt values and narrow disclosure to skills Two review findings, both of which made the previous commit wrong. BLOCKER (isolated adversarial review). Every manifest-supplied value interpolated into a consent-prompt line was rendered unescaped. Those lines are joined with \n and written RAW to stderr on the needs-consent path (capability-command-router -> cli-exit runMain), so a stem carrying a newline forged additional lines indistinguishable from genuine GSD disclosure text, and an ANSI escape could clear or rewrite lines already printed. That defeats the informed-consent guarantee this change exists to provide, and is a prompt-injection vector against any agent that reads the stderr text to decide whether to retry with --yes. The hole was not unique to the new class - hook event/script, command family/module/router, every MCP field, and every reviewer-lane field were equally unescaped. Fixing only the new one would have created the generative-fix divergence this repo tracks, so renderValueForPrompt is applied to all five classes through one helper, guarded by a parity test that fails if a future class skips it. Escaping is identity for ordinary names, so no well-formed manifest's output changes. The disclosure OBJECT stays verbatim - only the rendered LINE is escaped - because the signature and every consumer reasoning about identity depend on the declared value. NARROWED to skills only. The previous commit also collected agents, arguing ADR-2363 D3 classifies instruction surfaces as "skills, agents". Verified against staging: stageSkillsForRuntimeAsSkills takes a registry and unions third-party skills in via readInstalledCapabilitySkill, while stageAgentsForRuntimeWithConverter takes only a source directory and has no registry-aware path. Third-party agents are never staged into the instruction context, so disclosing them would have put a false claim in a security prompt - worse than the scope creep two reviewers flagged it as. D3's classification stands; D5 now records that Phase 1 implements the skills half and that whether agents should be staged at all is an open maintainer question. Also reverts the premature ADR-2363 ratification. The previous commit flipped it to Accepted and asserted "#3248 merged" while this branch IS #3248 and is unmerged. Status returns to Proposed, and the ADR-1244 back-link - owed only on ratification - is withdrawn. Adds the fast-check property suite CLAUDE.md requires and the direct precedent (reviewer-trust-disclosure) already had: totality, D4 signature invariance, D3 hasExecutable invariance, and renderer totality over adversarial manifests. Refs #3248 * chore(#3248): correct changeset scope claim and backfill pr number The fragment was written against the pre-narrowing commit and still advertised 'skills and agents'. 4d26887e narrowed disclosure to skills only - third-party agents are never staged into the instruction context - but did not touch the fragment, so the release notes would have carried a claim the code does not implement. Also backfills pr:0 -> 3253 and names the prompt-escaping fix, which is user-visible and was absent from the original body. Changeset-only; no code or test changed, so the gsd-test pass recorded for 4d26887e still describes this tree's behavior. Refs #3248 --------- Co-authored-by: sim <sim@local> |
||
|
|
ffd5370464 |
fix(#2903): use the command form that actually works in reader-facing docs (#3047)
* fix(#2903): use the command form that actually works in reader-facing docs Docs told readers to type the colon form, which no runtime registers -- 18 of 19 runtimes use slash-hyphen and the 19th uses shell-var -- so anyone copying an example got an unrecognized command. Swept 178 occurrences across 53 files, locale mirrors included so they do not re-diverge from English. The colon form is a source-authoring token, not a user-facing one: install-time converters key on it to produce the hyphen form runtimes actually register. So the sweep is scoped, and three things are deliberately left alone: - ADRs, which are a historical record; editing their prose falsifies what was written at the time. - The legacy release-notes archive, pending a maintainer decision on whether it follows the same historical carve-out. Excluding it keeps a later reversal additive rather than a revert. - Source artifacts under commands, workflows and agents, where the colon form is load-bearing. Rewriting those would break the installed-skill guarantee across every runtime -- the single largest hazard here. The plugin namespace form is a real, separate token and survives untouched. Adds a lint enforcing exactly that boundary, since the correct form genuinely differs by directory and nothing previously caught the drift. Also fixes a hardcoded colon form in the capability-matrix generator. The sweep alone would have left the generated matrix disagreeing with the template that produces it, so the fix is at the source and the output regenerated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(#2903): stop the sweep misquoting source frontmatter Adversarial review caught three lines where the sweep rewrote a citation of the literal YAML name: key from a source command file. That key genuinely is the colon form -- this change's own carve-out logic says source-authoring tokens keep it -- so the docs ended up misquoting the real files. One of the three is an acceptance-checklist assertion, which the sweep turned into a false statement. Restored the three citations to match their sources verbatim, surgically: where a line carried both a name: citation and a real reader-facing slash command, only the citation reverted and the command stayed corrected. The guard needed the same distinction, or it would have flagged the restoration and reddened the build: a gsd:<cmd> token preceded by name: is a citation of a source token and is now permitted. The exemption is deliberately narrow -- a bare gsd:<cmd> anywhere else still fails -- with a test pinning that narrowness. Also makes the detection case-insensitive. Review found /GSD:next slipped through silently; no such casing exists in the tree today, so this closes a latent gap rather than fixing a live one. Swept the whole tree for further corrupted citations: none beyond the three. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(#2903): retire the stale-next invariant and sweep next like every other command Maintainer decision on a genuine conflict between two contracts. Invariant #3054 banned the literal /gsd-next from user-facing docs because it named a retired workflow-advance command. But commands/gsd/next.md is a live command -- the state-aware smart-entry launcher -- and this issue requires docs to use the hyphen form every runtime actually registers. Both could not hold for this one command, so docs had been sidestepping the ban by keeping the colon form, which is exactly the defect this issue exists to remove. FEATURES.md already recorded the reassignment: the hyphen form "is not the retired workflow-advance command; it is reserved for the state-aware smart-entry launcher. Workflow advancement remains under /gsd-progress --next." With that reassignment the invariant's premise is obsolete and the guard now contradicts the documented command form, so it is retired with a comment recording why rather than deleted silently. next is now swept like every other command, and the earlier exemption added to the new guard is removed so nothing is special-cased. Four citations of the literal name: frontmatter key stay in colon form, because the source file really does carry name: gsd:next and a doc quoting it must reproduce it verbatim. Two of those lines were reworded to say which side is the frontmatter key and which is the slash command, since they previously conflated the two. Verified the retired scan would now genuinely fail against this tree -- the conflict was real and resolved, not dodged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * chore(#2903): backfill changeset pr number Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
557d46984e |
docs(#2782): how-to for declaring a reviewer lane in a capability (#2906)
* docs(#2782): how-to for declaring a reviewer lane in a capability ADR-2782 shipped the Reviewer Lane capability surface in 1.9.0, but the only documentation was reference (capability-manifest.md) and rationale (ADR-2782). A capability author had no task-oriented path from "I have a review CLI" to "/gsd:review invokes it". Adds docs/how-to/ship-a-reviewer-lane.md: role selection, the spawn and openai-http worked examples, federated config ownership, the review-lane query surface as the verification step, what the install disclosure and egress-host re-verification mean for the author, and the data-only boundary with the two named CLIs that do not fit today. Also corrects the manifest reference's `invoke` row, which understated three enums against the shipped validator: promptChannel omitted `argv`, effortChannel omitted `env`, and the openai-http sub-shape plus the required-with-file-arg `outputArg` were undocumented entirely. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(#2782): correct four claims found by the two orthogonal reviews Security review (1 major, 2 minor): - "a reserved slug" implied the gsd-/anthropic- namespace rule, which guards the capability id, not reviewer.slug. The slug guard is isReservedName (__proto__/constructor/prototype), a prototype-pollution barrier. Both rules are now stated and kept apart. - Added ADR-2782 D5's own caveat verbatim: disclosure and host pinning make the channel visible, pinned and revocable, not safe, and consent-at-install is a weaker gate for a standing egress channel than for a hook. - Named integrity/SHA pinning and engines.gsd as the controls that make the disclosure tamper-evident and the version range enforceable. Correctness review (1 major, 1 minor): - Claimed a name collision is "a hard failure at install". It is not. installCapability never runs validateCrossCapability; the check runs in loadRegistry, and a colliding overlay is dropped from acceptedMap with a warning while the install reports success. Documented as the quiet failure mode it is, with the symptom to look for. - The feature-only field list omitted hooks and activationKey, both of which FEATURE_FIELDS_FORBIDDEN_ON_REVIEWER rejects. Both worked examples re-validated against validateCapability() -> []. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(#2782): restore Kimi Code to the cross-AI reviewer list set-up-cross-ai-review.md named eleven reviewers; twelve lanes ship. The kimi-code lane (added by #2718, declared as manifest data by #2798) was never added here — the same roster-drift class as #2781, which #2800's parity gate covers for COMMANDS.md and FEATURES.md but not for how-to prose. Also points readers at the declared-lane model rather than a static list: the roster is now generated, a capability can ship its own lane, and `gsd-tools review-lane sections` answers "what do I actually have". Verified against the twelve declared bodies in capabilities/*/capability.json. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(#2782): use the invocation form the runtime descriptors actually declare The new guide used /gsd:review. Nothing in this repo produces that form. - capability-validator VALID_COMMAND_STYLES is {slash-hyphen, shell-var}; there is no colon/namespaced style in the vocabulary at all. - 18 of 19 runtime capabilities declare commandStyle "slash-hyphen", claude included; codex is "shell-var". Every artifactLayout prefix is "gsd-". - A plain-file command install never namespaces, so .claude/commands/ gsd-review.md is typed /gsd-review. - The Claude Code plugin surface would namespace on plugin.json "name", which is "gsd-core" -- so the plugin form would be /gsd-core:review. The commands/gsd/ subdirectory is cosmetic and contributes nothing to the invoked name. So /gsd:review is neither the installed form nor the plugin form. Uses /gsd-review, matching set-up-cross-ai-review.md and the 18 descriptors. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(#2782): state that lane listing is not wired yet The guide could describe authoring, validating, and installing a lane but implied a publishing path that does not exist. Neither discoverability catalog can accept one: a Community Capability Registry entry requires a non-empty loopExtensionPoints plus hookKinds, and a role:"reviewer" capability is forbidden from declaring steps/contributions/gates, so both fields are unsatisfiable rather than merely unset. The EoS Registry is ADR-1239 host integrations, which a lane is not. The registry schema predates the reviewer role by 17 days (#2182 Jul 11, ADR-2782 Jul 28) and registry-schema.cjs has zero occurrences of "reviewer". Tracked for a 1.9.x point release by #2904. Says so explicitly, and tells authors NOT to file a loop extension point they do not use to get past validation -- a schema satisfiable only by lying is one that will be lied to. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(#2782): backfill PR number and fix the changeset invocation form pr: 0 -> 2906. Also corrects /gsd:review -> /gsd-review in the fragment body. The fragment renders into CHANGELOG.md, which is a reader-facing docs surface and is never passed through the install-time converter -- so the colon form would ship the #2903 drift into a permanent release artifact. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs(#2907): propagate the invocation-form fix and restore lane order Two findings from an isolated review of the post-review delta. - docs/README.md and develop-a-capability.md still said /gsd:review in the cross-links added for the new guide. The form was corrected in the guide itself but not in the two entries pointing at it, leaving three docs making the same claim in two different forms. - set-up-cross-ai-review.md inserted Kimi Code between Antigravity and Ollama. REVIEWER_LANES is ordered by write_reviews order and kimi-code is 12th, appended after llama_cpp; the prose list mirrored declaration order before this change and now does again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Test <test@example.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
7372d99a26 |
enhance(#2800): derive reviewer flag lists and gate reviewer lane docs across locales (#2882)
* chore(#2800): derive reviewer flag lists and gate reviewer lane docs across locales The reviewer lane roster was hand-enumerated across five documentation surfaces and three workflow files that had drifted apart: --kimi-code was missing from all four translated COMMANDS.md mirrors, --coderabbit from every workflow forwarding list, and --antigravity from FEATURES.md. Adds checkReviewerDocsParity, a second pure gate deliberately separate from checkReviewerLaneParity so a stale doc cannot make the runtime checker look red. Workflows now derive their flag lists from a new review-lane flags query instead of hand-enumerating them, which also retires the unanchored grep that matched --agy inside --antigravity. Documents the previously absent reviewer body and hostBehaviors field in the capability manifest reference. Closes #2800 Closes #2781 Closes #2272 * fix(#2800): key the docs parity table arm on first-cell position Review found the flag arm was file-scoped, so the forwarding row that lists every flag in its third cell satisfied it on its own. Deleting a lane's own reviewer-table row -- the #2781 regression this gate exists to prevent -- therefore passed undetected. Arm 4 keys on the FIRST table cell, which separates a lane row from the forwarding row structurally and in every locale. Regression test included. * fix(#2800): shape-filter the flags subcommand output All three consumers read review-lane flags through an unquoted command substitution so the output word-splits into loop items. Phase 2 admits third-party overlay lanes, so an overlay flag containing whitespace would inject a second loop item and one containing a glob would expand against the cwd. Emit only well-formed flags so neither reaches the shell. * fix(#2800): remove the regex length ceiling and count only prose mentions Review found two real defects in the docs parity gate. The never-throws contract was false: building a RegExp from a declared flag or section title throws SyntaxError past ~100k chars, and Phase 2 admits overlay lanes whose declared strings are untrusted in length. Every one of these matches is literal, so String.includes replaces the regex outright, which also deletes escapeLiteral and the llama.cpp escaping it existed for. Arm 1 was context-blind: a flag mentioned only inside a fenced example or a commented-out row counted as documented. Both are stripped before matching. Also advertises all 13 lane flags in the argument-hint and corrects a stale eleven-lane count in the slug grammar note. * test(#2800): repoint the convergence suite off deleted workflow text The derived flag loop deleted the literal per-flag grep lines four tests matched on. Two of those failed loudly. The behavioral and property tests failed SILENTLY instead: their end marker no longer resolved, so the parse block extracted empty and both passed vacuously, and the property test's gsd_run stub had a no-op default that hid it. All now share one extractor and execute the real deployed block through a gsd_run shim backed by the actual binary. The whitelist assertions become an anti-parity check: re-adding a hand-written flag list must fail. Also repairs two vacuous cases in the docs parity suite. The unreadable-doc test called its own mock rather than the reader, and the integration test bounded nothing, so a doc losing its marker would have been silently skipped and still passed green. * fix(#2800): run the derived flag loop after the launcher preamble The remote matrix caught a real runtime bug, not a test artifact. In autonomous.md and plan-review-convergence.md the launcher preamble that defines gsd_run lives in a separate, LATER bash fence than the derived loop. Each fence is its own shell, so gsd_run was undefined where the loop ran: the command substitution yielded nothing and zero reviewer flags would have been forwarded. Worse than the drift this epic fixes, and silent. The whole CONVERGENCE_ARGS construction moves as one unit, because the --max-cycles append sits between the loop and the preamble and would otherwise have run against an uninitialized variable and then been dropped by the relocated initializer. Also documents all 13 lane flags in help/modes/full.md, which the repo gates bidirectionally against each command's argument-hint. * test(#2800): repoint the two converge suites off deleted flag literals Both asserted workflow.includes('--codex') against the hand-enumerated list the derived loop removed. They now assert the derivation itself, keep --all and --text (convergence controls, still literal), and add an anti-parity guard so re-adding a hardcoded list fails. The lost pass-through proof is replaced with a real one: every flag the tests used to hardcode is asserted present in the actual roster emitted by the binary, which is the property the old assertion was protecting. * test(#2800): acknowledge the workflow byte growth from the derived flag loop * chore(#2800): backfill changeset pr number to 2882 * fix(#2800): strip HTML comments to a fixed point in the parity gate CodeQL js/incomplete-multi-character-sanitization (high) on PR #2882: the single-pass <!--...--> strip can leave a live <!-- behind, so a join-trick construction smuggles a commented-out row past the gate and it counts as documented. Not an injection risk here since nothing is rendered, but it is the exact false pass this helper exists to prevent. Strips to a fixed point, then treats any surviving opener as unterminated so the multi-line branch closes it on a later line. Terminates because every pass strictly shortens the string. * test(#2800): pin the comment-smuggling regression with a real reproducer The obvious fixture for this class does not reproduce it: <!--<!---->--> leaves a dangling --> rather than a live <!--, and is caught either way, so it would have passed with and without the fix. The join-trick construction (<!- + <!--DUMMY--> + -...-->), the <scr<script>ipt> shape, genuinely regresses on the single-pass strip and is what the test now uses. --------- Co-authored-by: Test <test@example.com> |
||
|
|
5695522d5f |
feat(#2096): migrate Antigravity onto EoS declarative adapter + permission-writer + MCP companion (ADR-1239)
Fold all antigravity literal branches into descriptor-driven reads: getConfigDirFromHome (→ configHome.kind 'dot-home-nested'), projectLocalHookPrefix (→ hostBehaviors.hookPathStyle 'raw'), applyAgentPathRewrites (→ noPathRewrite), getProjectInstructionFile (→ projectInstructionFile 'GEMINI.md'); removed the dead inline convertClaudeAgentToAntigravityAgent branch + dead isAntigravity destructures (antigravity is already on the descriptor-agents path). subagentToolkit flipped undocumented→full (Context7: antigravity.google/docs/cli/features); namedDispatch/nested/maxDepth/backgroundDispatch stay undocumented. Byte-identical golden parity for all 16 runtimes. UPGRADE 1 (permission-writer): permissionWriter 'antigravity' + configureAntigravityPermissions merges a scoped permissions.allow block (GSD's own tree + hooks) into Antigravity's settings.json — non-destructive, idempotent, symmetric uninstall. Added to VALID_PERMISSION_WRITERS + the FinishPermissionWriter union. UPGRADE 2 (MCP companion): configureAntigravityMcpConfig writes mcp_config.json registering the gsd-core companion MCP server (Gemini-successor mcpServers schema, best-effort — raw schema unpublished). Both writers dispatch from finishInstall. settings.json is golden-excluded (HOOK_CONFIG_FILES); mcp_config.json (portable, no absolute paths) is golden-tracked → only antigravity.json changes. Tests: declarative-reference-antigravity extended (source-grep guard across 4 modules, fail-closed for the 4 undocumented sub-axes, validator acceptance) + antigravity-upgrades (permission-writer + mcp_config live-install, idempotency, user-preservation). Matrix + ADR-1016 + capability-manifest + CONTEXT.md + connect-gsd-mcp-server docs updated; changeset (Changed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
ab04916682 |
feat(#2095): migrate Kimi CLI onto EoS imperative adapter + native hook-bus + background dispatch (ADR-1239)
Fold all runtime==='kimi'/isKimi logic branches into descriptor-driven hostBehaviors (localInstallDeferred, verificationStyle, agentManifestStyle, reapplyCommand, doneBannerStyle) + add 'kimi' to _DESCRIPTOR_AGENTS_RUNTIMES. Kimi's skills/kimi-agents dispatch was already descriptor-driven (converter-by- name + kimi-agents kind). Zero isKimi/runtime==='kimi' branches remain. UPGRADE 1 (native hook bus): new hooksSurface 'kimi-hooks-toml' + a marker- delimited config.toml [[hooks]] emitter (buildKimiHooksTomlBlock/writeKimiHooksToml in runtime-hooks-surface.cts; resolveKimiHooksTomlDir in runtime-homes.cts). GSD's lifecycle hooks now wire into Kimi's native ~/.kimi/config.toml (Context7- confirmed path) at SessionStart/PreToolUse/Stop/PreCompact/SubagentStart/ SubagentStop — kimi becomes a hooks/ consumer (the 3 && !isKimi exclusion guards removed). config.toml holds absolute install paths so it's golden-excluded via an exact relative-path (.kimi/config.toml), not a basename (which would blind Codex's config.toml). New hooksSurface value added to the closed enum in capability-validator + runtime-config-adapter-registry. UPGRADE 2 (background dispatch): flip dispatch.backgroundDispatch true (Kimi's Agent tool takes run_in_background; root agent already gets the Agent tool), so negotiation no longer flattens dispatch. subagentToolkit stays 'undocumented' per AC (coder/explore/plan have distinct tool policies). MCP transport explicitly deferred (no installer-driven MCP for any runtime). Golden: only kimi.json changes (hooks/ scripts now installed); all 15 others + claude-local byte-identical (kilo/zcode keep their own exclusions). Tests: kimi-imperative-reference (adapter/axes/fail-closed/hostBehaviors + source-grep guard) + kimi-upgrades (config.toml [[hooks]] SessionStart + marker idempotency + backgroundDispatch negotiation). CONTEXT.md glossary + matrix + how-to updated; changeset (Added). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
a3d3c2a445 |
refactor(#1756): derive getDirName from a documented runtime.localConfigDir descriptor axis (#1757)
ADR-1239 Phase B (parent #1679). getDirName was a hand-maintained 15-branch if-chain mapping each runtime to its local content-rewrite dot-dir. Relocate those values into a documented runtime.localConfigDir descriptor field; derive getDirName from registry.runtimes[id].runtime.localConfigDir (fallback .claude). - 16 capability.json gain runtime.localConfigDir (byte-identical values) - capability-validator.cjs requires it (non-empty dot-dir); registry regenerated - docs/reference/capability-manifest.md documents the field + the three divergent values (copilot=.github, antigravity=.agents, kimi=.kimi-code) - drift-guard test: golden value map + key-set equality both ways Byte-identical install output for all 16 runtimes (golden-parity harness #1730). Closes #1756 Co-authored-by: review-bot <review-bot@gsd> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
02c6491e61 | docs(#1464): fix ADR-1244 capability doc set — followable tutorials, overlay-model + install tutorial, set/fragment/runtimeCompat reference, accuracy fixes | ||
|
|
08d1c57d6e |
fix(#1460): verify-or-reject capability --integrity per source; confine hook commands to the bundle
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
dcceb1a004 |
fix(#1441): antigravity resolver prefers GSD-owned dir over first-existing (#1442)
* fix(#1441): antigravity resolver prefers GSD-owned dir over first-existing resolveConfigHomeFromDescriptor's dot-home-nested probe returned the first bare-existing candidate, so a CLI user (~/.gemini/antigravity-cli) who also had the IDE's ~/.gemini/antigravity dir was silently shadowed to the legacy dir (probed first). Regression from #217 — pre-#217 returned ~/.gemini/antigravity unconditionally. Add an optional probeMarker (gsd-core/VERSION) to the dot-home-nested descriptor: a two-pass probe prefers the candidate GSD installed into, then bare existence, then probe[0]. Behavior is byte-identical when probeMarker is absent (windsurf etc. unaffected). Adds detectAntigravityDirAmbiguity() for installer/operator guidance on already-misinstalled users (auto-relocation ruled out per ADR-0008's single-configDir migration bound). Regression tests fail before / pass after: coexistence + marker-priority cases, end-to-end through the registry descriptor. Claude-Session: https://claude.ai/code/session_01JU2WB23JLE3QTysPXuFJjB * chore(#1441): add changeset for antigravity resolver fix Claude-Session: https://claude.ai/code/session_01JU2WB23JLE3QTysPXuFJjB |
||
|
|
f52a7a5f77 |
feat(#1245): add capability ecosystem ADR, PRD, and developer documentation (#1248)
Phase 0 of the Capability Ecosystem epic (#1244): the design record and the third-party-author documentation set, with no runtime or code changes. - docs/adr/1244-capability-ecosystem.md — architecture decision record (amends/extends ADR-857 Decisions 7 & 8) - docs/prd/1244-capability-ecosystem.md — product requirements - Diataxis docs: tutorial, how-to (publish/import/version/remove), reference (manifest schema, /gsd:capability command, capability matrix), explanation (trust model); cross-links added to develop-a-capability.md Refs #1244 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |