Research — tech-agnostic-language-fallback-01M3NP53
Grounded on main f13a799c by the pre-planning squad (code-truth, foldables, campsite) and the post-spec squad (scope/sizing, fakeability). Reproductions live in the session scratchpad; commands are summarised here.
Reproductions (CLI 4.0.0rc5)
- Zig charter:
answers.yamllanguages_frameworks: "Zig 0.16.0 is the primary implementation language.",available_tools: [git, spec-kitty, zig]→charter generate --from-interview --jsonsucceeds with diagnosticIgnored unknown available_tools: zig;catalog.languagesABSENT → bootstrap context listspython-conventions,python-mutation-tools,python-review-checks(None = admit all). - Stale path (#4614): add
testing_requirements: "pytest for helper scripts."→generate --force→['python']; correct back to Zig →generate --force→ still['python']; compact context- Languages: python. - Review (#5283): Zig-only merged mission,
spec-kitty review --mode lightweight|post-merge→✗ Dead-code scan: undeterminable (MISSION_REVIEW_DEAD_CODE_UNDETERMINABLE)reason "changed source set contains no supported Python files",Verdict: fail, rc=1. Addingtests/test_build.py→ still undeterminable. Addingscripts/gen.pywith an unreferenced def → scanned,pass_with_notes.
Decisions
D1 — Unknown-language representation
- Decision: reserved
unknowntoken incatalog.languages(operator). - Rationale: keeps the load-bearing #3292 contract (
None= admit all,[]= admit none) intact;unknownis an explicit third state that admits no language-scoped artifacts under the existing overlap rule and is detectable for the advisory. - Alternatives: separate
language_statusfield (two fields to keep consistent); reuse[](loses the advisory signal; collides with hand-edited admit-none).
D2 — Detection rule without a language list
- Decision: only the languages/frameworks answer may signal
unknown, when no recognised language matched anywhere, the answer is non-empty, differs from the shipped default, and is not a placeholder. - Rationale: the shipped default answer is non-empty prose naming no language — a naive "non-empty + no match" rule would turn every defaults-built charter into admit-none (post-spec MAJOR). Free-prose answers can only add recognised languages.
- Alternatives: structured languages field (out of scope, #4613 remainder); "unknown whenever no match" (rejected: #3292 trap).
- Known accepted false label: a framework-only answer ("Django") →
unknown; the advisory tells the user to extend their charter.
D3 — #4614 precedence
- Decision:
infer_repo_languages(..., prefer_interview=True)only fromcompile_charter(rederive_languages=True), set only bycharter generatewith--from-interview(the default). - Rationale: #2395 decided runtime reads must be compiled-first; flipping globally reopens it. The compile-time bypass is the minimal honest fix. Guard tests
test_language_scope.py:49,test_active_languages_idempotency.py:185/:196stay unchanged. - Alternatives: mtime-based (fragile under git), explicit reset flag (undiscoverable).
D4 — Dead-code not applicable
- Decision: gate result
skip, findingdead_code_not_applicable, codeMISSION_REVIEW_DEAD_CODE_NOT_APPLICABLE, verdictpass_with_notes(operator). - Rationale: #2987 FR-015 ("never a false clean zero") holds because the state is distinct and visible; genuine undeterminable stays a failure. A Python mission with only test/doc changes is also not applicable (nothing to decide) — deliberate, documented.
D5 — pytest pre-check
- Decision: warn, do not exit. No gate needs pytest (verified: lane check, dead-code string scan, BLE001 audit, issue matrix; env-skew compares typer/click only).
D6 — Hyphen rule (#4613 minimal)
- Decision: prefix every language pattern with a
(?<!\w-)guard so a token preceded byword-does not match; trailing compounds ("Java-based") unchanged.
D7 — Advisory placement
- Decision: product-code constant in
charter.activation, rendered once per context render (compact + bootstrap); docs page underdocs/guides/how-to/governance/. - Rationale: avoids built-in pack edits (graph regen, #5202 owner collision);
docs/is published, not shipped in the wheel, so the advisory names the page rather than a repo path.
D8 — Tool message
- Decision: per-label message for
available_toolsonly; registry not widened (operator).
Adversarial evidence
No dependency decision → supply-chain adversarial pass not applicable. Post-spec squad dispositions: all MAJOR findings accepted (folded into spec); sizing ~4× accepted (lane plan); migration or [] latent bug deferred_with_rationale → follow-up #5335.